gpt4 book ai didi

entity-framework - Automapper 和 Entity Framework

转载 作者:行者123 更新时间:2023-12-04 16:10:36 25 4
gpt4 key购买 nike

我在使用 Automapper 和 Entity Framework 时遇到了两个问题,我想知道我的解决方案是否是最好的。

语境 :

我有一个 ObjectA其中有 ObjectB 的列表它又具有 ObjectC .
ObjectC是数据库中的一个列表,就像国家一样。我可以改变ObjectCObjectB但我不加想加ObjectC .

我使用 MVVM 和 ObjectB列在数据网格中。有组合框可供选择ObjectC .

我想保存 ObjectAObjectB同时,我使用 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();
}

Entity Framework 类:
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不应该更新。但是,它可以工作(即:更新正常,他不会尝试在数据库中添加一行,Automapper/EF 可以在数据库中找到 ObjectC 并在 ObjectCID 上更新 ObjectB ...)

注意:它也适用于我的第二个问题的第一点的解决方案。

第二题 :当我在数据网格上更新、添加或删除一行时,我想将更改保存在数据库中。
  • 更新:与第一个问题相同:该行已经存在。
    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 docs 中的一些内容作为明星。 :

    Currently, AutoMapper is geared towards model projection scenarios to flatten complex object models to DTOs and other simple objects, whose design is better suited for serialization, communication, messaging, or simply an anti-corruption layer between the domain and application layer



    也就是说,如果您仔细阅读,automapper 旨在从复杂对象转换为更简单对象,或者在行之间读取,从实体对象到 Pocos、DTO、ViewModel 等……而不是相反。为什么?只是因为它太复杂了。这不是你可以拥有 new ObjectA()的情况.

    问题一:
    这是 Entity Framework(和其他主流 Orms)的预期行为。 EF 处理实体对象。如果您指定 ObjectC 属性是一个新实体,EF 将尝试插入它。如果你想使用一个已经存在的,你需要先从上下文中加载它,或者干脆使用 ObjectCId 外键。

    问题2:
    这实际上与问题 1 的答案几乎相同。EF 旨在让您使用实体对象。当您修改它们时,EF 跟踪更改,然后在您调用 SaveChanges() 之后,那些被持久化在数据库中。

    只是关于删除的特别说明。 EF 不会级联删除,例如 NHibernate 上的“cascade=all-delete-orphan”。有一些 workarounds ,但一般来说,当您想要删除整个关系时,您需要管理子项的删除。

    我知道这可能不是您正在寻找的答案,但是您正在处理由于您没有正确使用工具而引发的问题。

    一般来说,使用 EF 很简单:

    1 - 从数据库加载实体

    2 - 修改它们

    3 - 通过调用 SaveChanges() 在数据库上应用更改

    关于entity-framework - Automapper 和 Entity Framework ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19518493/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com