Bon*_*eil 6 entity-framework automapper
我在Automapper和Entity Framework中遇到了两个问题,我想知道我的解决方案是否是最好的解决方案.
背景:
我有ObjectA一个列表,ObjectB其中依次有一个ObjectC.
ObjectC是数据库中的列表,如国家/地区.我可以改变ObjectC,ObjectB但我不想添加ObjectC.
我使用MVVM ObjectB并列在数据网格中.有组合框可供选择ObjectC.
我想保存ObjectA并ObjectB同时使用Automapper和事务.
    public void SaveObjectA(ObjectA p_ObjectA)
    {
        OpenTransaction();
        var l_Provider = new DataProvider<DB.ObjectA>(Context);
        var l_ObjectA = l_Provider.FindById(p_ObjectA.ID);
        Mapper.Map(p_ObjectA, l_ObjectA);
        CloseTransaction();
    }
实体框架类:
public partial class ObjectA
{
    public ObjectA()
    {
        this.ObjectB = new HashSet<ObjectB>();
    }
    public System.Guid ID { get; set; }
    public virtual ICollection<ObjectB> ObjectB { get; set; }
} 
public partial class ObjectB
{
    public System.Guid ID { get; set; }
    public System.Guid ObjectCID { get; set; }
    public virtual ObjectC ObjectC { get; set; }
}
public partial class ObjectC
{
    public System.Guid ID { get; set; }
    public string Name { get; set; }
}
DTO课程:
public class ObjectA : ObjectBase
{
    public ObjectA ()
    {
        ObjectB = new Collection< ObjectB >();
    }
    public virtual ICollection<ObjectB> ObjectB { get; set; }
}
public class ObjectB : ObjectBase
{
    private ObjectC  _ObjectC { get; set; }
    public virtual ObjectC ObjectC
    {
        get
        {
            return _ObjectC;
        }
        set
        {
            _ObjectC = value;
        }
    }
}
public class ObjectC : ObjectBase
{
    public string Name { get; set; }
}
public abstract class ObjectBase
{
    public Guid ID { get; set; }
} 
第一个问题:当我保存时ObjectB,Entity Framework尝试插入ObjectC.但ObjectC已经存在.我不想要插入但需要更新.
我的解决方案(在论坛上看到):
Mapper.CreateMap<ObjectB, DB.ObjectB>()
      .ForMember(pro=>pro.ObjectC, opt=>opt.Ignore());
但我不明白,因为如果我忽略ObjectC,ObjectC不应该更新.然而,它的工作原理(即:更新OK,他不尝试在数据库中添加行和Automapper/EF可以找到ObjectC数据库和更新ObjectCID上ObjectB...)
注意:它也适用于我的第二个问题的第一点的解决方案.
第二个问题:当我在datagrid上更新,添加或删除一行时,我想保存数据库中的更改.
更新:与第一个问题相同:该行已存在.
Mapper.CreateMap<ObjectB, DB.ObjectB>()
      .ConstructUsing(s => Context.Set<DB.ObjectB>().Find(s.ID));
我认为,解决方案是从数据库中附加正确的行,然后填充属性.
所以我ConstructUsing用来找到这一行.
添加:然后,ID为空,我无法保存新行
Mapper.CreateMap<ObjectB, DB.ObjectB>()
      .ConstructUsing(s => Context.Set<DB.ObjectB>().Find(s.ID) ?? 
                               Context.Set<DB.ObjectB>().Create())
在行不存在的情况下,我必须创建(并附加)对象到上下文.
删除:数据网格中删除的行不会在数据库中删除:
Mapper.CreateMap<ObjectA, DB.ObjectA>()
      .ConstructUsing(s => Context.Set<DB.ObjectA>().Create())
      .AfterMap
      (
          (bef, aft) => aft.ObjectB.ToList()
              .Where(x => !bef.ObjectB.Select(z=>z.ID).Contains(x.ID))
              .ToList()
              .ForEach(ele => Context.ObjectB
                                     .Remove(Context.ObjectB.Find(ele.ID)))
      );
所以,它有效,但我想知道你会怎么做,一个更简单的方法.
好吧,在深入探讨您的问题之前,让我先引用 Autommaper文档中的一些内容:
目前,AutoMapper面向模型投影场景,将复杂的对象模型扁平化为DTO和其他简单对象,其设计更适合序列化、通信、消息传递,或者只是域和应用层之间的反腐败层
也就是说,如果你仔细阅读,automapper 的设计目的是从复杂的对象转换为更简单的对象,或者读取字里行间的内容,从实体对象到 Pocos、DTO、ViewModel 等……而不是相反。为什么?仅仅是因为它太复杂了。这不是你可以拥有一个的情况new ObjectA()。
问题 1:这是 Entity Framework(和其他主流 Orms)的预期行为。EF 处理实体对象。如果您指定 ObjectC 属性是一个新实体,EF 将尝试插入它。如果您想使用现有的外键,则需要首先从上下文中加载它,或者简单地使用 ObjectCId 外键。
问题 2:这实际上与问题 1 的答案几乎相同。EF 是为您使用实体对象而设计的。当您修改它们时,EF 会跟踪更改,然后在调用后SaveChanges(),这些更改将保留在数据库中。
只是关于删除的特别说明。EF 不级联删除,如 NHibernate 上的“cascade=all-delete-orphan”。有一些解决方法,但一般来说,当您想要删除整个关系时,您需要管理子项的删除。
我知道这可能不是您正在寻找的答案,但您正在处理由于没有正确使用工具而出现的问题。
一般来说,使用 EF 很简单:
1 - 从数据库加载实体
2 - 修改它们
3 - 通过调用对数据库应用更改SaveChanges()
| 归档时间: | 
 | 
| 查看次数: | 2527 次 | 
| 最近记录: |