C# 如何从新创建的分离实体更新实体

C# 如何从新创建的分离实体更新实体,c#,.net,linq-to-sql,C#,.net,Linq To Sql,假设我创建了一个新产品,如下所示: Product p=new Product(){ Id= 2,Name="some name"}; 我的产品变量从未附加到数据上下文,如何附加此实体,以便数据库中Id=2的现有产品使用我分离的产品的名称进行更新?我希望类似的方法也能奏效 Datacontext db = new Datacontext(); // replace with your DataContext Product originalProduct = db.Pr

假设我创建了一个新产品,如下所示:

Product p=new Product(){ Id= 2,Name="some name"};

我的产品变量从未附加到数据上下文,如何附加此实体,以便数据库中Id=2的现有产品使用我分离的产品的名称进行更新?

我希望类似的方法也能奏效

 Datacontext db = new Datacontext(); // replace with your DataContext
 Product originalProduct = 
         db.Products.Single(p => p.Id == 2); // get product with Id 2

 originalProduct.Name = "SomeName";  // only reset Name prop
 originalProduct = p;                // or you may assign p to originalProduct
 db.SubmitChanges();                 // submit changes to DB

更简单的解决方案是在您希望这样工作的实体上实现
ICloneable
接口。然后,您只需将Clone()调用到从数据库中提取的“原始”实体中

例如:

class Product : ICloneable
{
    public virtual int Id { get; private set; }
    public virtual string Name { get; set; }

    public object Clone()
    {
        return new Product() { Id=this.Id, Name=this.Name };
    }
}
然后你需要做的就是:

Datacontext db = new Datacontext(); // replace with your DataContext
Product originalProduct = 
        db.Products.Single(p => p.Id == 2); // get product with Id 2

db.originalProduct = p.Clone()
db.SubmitChanges();
编辑: 我在工作中遇到了同样的问题,到目前为止,我找到的最优雅的解决方案是构建一个扩展方法,该方法接收新创建的实体(在您的例子中是
产品
),并将其属性(标识符除外)复制到从DataContext中提取的实体

我通过反射复制了所有属性,这样,如果我更新了实体,那么扩展方法仍然有效

希望这对你也有帮助


如果你能找到一个更优雅的方法来解决这个问题,我想听听:)

再加上gillyb的帖子和我留下的评论。克隆实体的一种非常简单的方法是:

Private Function CloneEntity(Of TEntity)(ByVal entity As TEntity) As TEntity

    Dim dataContext As New DataContext()
    Dim entityType As System.Type = GetType(TEntity)

    ' If the purpose of the clone is just to attach it the existing entity to a new
    ' DataContext, you can use IdentityMembers in place of PersistantDataMembers. Setting
    ' only the IdentityMembers is enough to allow for attaching the clone as an "originaL"
    ' entity to the DataContext.
    Dim dataMembers = dataContext.Mapping.GetTable(entityType).RowType.PersistentDataMembers

    Dim clone As TEntity ' Do something here to create an entity of the desired type. 
    Dim boxedClone As Object = clone

    For Each dm In dataMembers

         ' Depending on how your ColumnAttribute is set, you would use StorageAccessor if
         ' the Storage property is set. Otherwise, you would use MemberAccessor instead.
          dm.StorageAccessor.SetBoxedValue(boxedClone, dm.StorageAccessor.GetBoxedValue(entity))
    Next

    Return clone

End Function
Dim dataContext As New DataContext()
dataContext.GetTable(Of Object)().Attach(entityToUpdate, CloneEntity(entityToUpdate))
dataContext.SubmitChanges()
那么您只需要执行以下操作:

Private Function CloneEntity(Of TEntity)(ByVal entity As TEntity) As TEntity

    Dim dataContext As New DataContext()
    Dim entityType As System.Type = GetType(TEntity)

    ' If the purpose of the clone is just to attach it the existing entity to a new
    ' DataContext, you can use IdentityMembers in place of PersistantDataMembers. Setting
    ' only the IdentityMembers is enough to allow for attaching the clone as an "originaL"
    ' entity to the DataContext.
    Dim dataMembers = dataContext.Mapping.GetTable(entityType).RowType.PersistentDataMembers

    Dim clone As TEntity ' Do something here to create an entity of the desired type. 
    Dim boxedClone As Object = clone

    For Each dm In dataMembers

         ' Depending on how your ColumnAttribute is set, you would use StorageAccessor if
         ' the Storage property is set. Otherwise, you would use MemberAccessor instead.
          dm.StorageAccessor.SetBoxedValue(boxedClone, dm.StorageAccessor.GetBoxedValue(entity))
    Next

    Return clone

End Function
Dim dataContext As New DataContext()
dataContext.GetTable(Of Object)().Attach(entityToUpdate, CloneEntity(entityToUpdate))
dataContext.SubmitChanges()

这肯定会起作用,但总是复制属性可能会很痛苦。在NHibernate中,他们有一个名为RETACH的构造,可以让您指定它是DB中的一个现有对象,我不确定L2S是否有这个。DB.originalProduct似乎不正确。。。当您将p.Clone()分配给originalProduct时,它将不再“附加”到上下文,因此它将不会被持久化。哦,您是对的,我没有完全考虑清楚。。。我会检查一下并试着修复它。我在工作中遇到了同样的问题,所以我需要想出一个好的解决方案,当我这样做的时候,我会解决它的!:)谢谢如果要跳过使用反射,还可以使用DataContext的MappingSource将值复制到新的克隆版本。这样,它只会复制特定于数据库的属性。另外,我认为您正在寻找DataContext.GetTable().Attach(原始,新)在这里。没问题!我将把我用作另一个答案的代码发布到您的答案上:)