当我在纯 EF4 代码中具有一对多映射时,可以隐藏 ICollection 字段吗?

2024-06-18

我的具有一对多映射的域类通常采用以下形式(未经测试的代码):

public Customer Customer
{
    // Public methods.

    public Order AddOrder(Order order)
    {
        _orders.Add(order);
    }

    public Order GetOrder(long id)
    {
        return _orders.Where(x => x.Id).Single();
    }

    // etc.

    // Private fields.

    private ICollection<Order> _orders = new List<Order>();
}

The 仅 EF4 代码示例 http://weblogs.asp.net/scottgu/archive/2010/07/16/code-first-development-with-entity-framework-4.aspx我见过在处理一对多关系时暴露了公共 ICollection。

有没有办法通过公开来保存和恢复我的收藏?如果没有,我的领域对象将被设计为满足 ORM 的要求,这似乎违背了我们的努力精神。公开 ICollection(及其 Add 等方法)似乎不是特别干净,也不是我的默认方法。

Update

Found 这个帖子 http://social.msdn.microsoft.com/Forums/pl-PL/adonetefx/thread/8e89e678-bc8b-478d-a322-aa8fa711f5b7这表明五月是不可能的。当然,微软发帖者确实表示他们正在“强烈考虑实施”它(我希望如此),而且我们已经过去了半年,所以也许已经取得了一些进展?


我发现无论做什么,EF 都需要ICollection<T>公开。我认为这是因为当从数据库加载对象时,映射会查找集合属性,获取集合,然后调用Add集合的方法来添加每个子对象。

我想确保添加是通过父对象上的方法完成的,因此创建了一个包装集合、捕获添加并将其定向到我首选的添加方法的解决方案。

延长一个List和其他集合类型是不可能的,因为Add方法不是虚拟的。一种选择是延长Collection类并覆盖InsertItem方法。

我只关注Add, Remove, and Clear的职能ICollection<T>接口,因为它们是可以修改集合的接口。

首先,是我的基本集合包装器,它实现了ICollection<T>界面 默认行为是普通集合的行为。但是,调用者可以指定替代方案Add被调用的方法。此外,调用者可以强制执行Add, Remove, Clear通过设置替代项来不允许操作null。这导致NotSupportedException如果有人尝试使用该方法,则会被抛出。

抛出异常不如从一开始就阻止访问好。但是,应该对代码进行测试(单元测试),并且会很快发现异常并进行适当的代码更改。

public abstract class WrappedCollectionBase<T> : ICollection<T>
{

    private ICollection<T> InnerCollection { get { return GetWrappedCollection(); } }

    private Action<T> addItemFunction;
    private Func<T, bool> removeItemFunction;
    private Action clearFunction;


    /// <summary>
    /// Default behaviour is to be like a normal collection
    /// </summary>
    public WrappedCollectionBase()
    {
        this.addItemFunction = this.AddToInnerCollection;
        this.removeItemFunction = this.RemoveFromInnerCollection;
        this.clearFunction = this.ClearInnerCollection;
    }

    public WrappedCollectionBase(Action<T> addItemFunction, Func<T, bool> removeItemFunction, Action clearFunction) : this()
    {
        this.addItemFunction = addItemFunction;
        this.removeItemFunction = removeItemFunction;
        this.clearFunction = clearFunction;
    }

    protected abstract ICollection<T> GetWrappedCollection();

    public void Add(T item)
    {
        if (this.addItemFunction != null)
        {
            this.addItemFunction(item);
        }
        else
        {
            throw new NotSupportedException("Direct addition to this collection is not permitted");
        }
    }

    public void AddToInnerCollection(T item)
    {
        this.InnerCollection.Add(item);
    }

    public bool Remove(T item)
    {
        if (removeItemFunction != null)
        {
            return removeItemFunction(item);
        }
        else
        {
            throw new NotSupportedException("Direct removal from this collection is not permitted");
        }
    }

    public bool RemoveFromInnerCollection(T item)
    {
        return this.InnerCollection.Remove(item);
    }

    public void Clear()
    {
        if (this.clearFunction != null)
        {
            this.clearFunction();
        }
        else
        {
            throw new NotSupportedException("Clearing of this collection is not permitted");
        }
    }

    public void ClearInnerCollection()
    {
        this.InnerCollection.Clear();
    }

    public bool Contains(T item)
    {
        return InnerCollection.Contains(item);
    }

    public void CopyTo(T[] array, int arrayIndex)
    {
        InnerCollection.CopyTo(array, arrayIndex);
    }

    public int Count
    {
        get { return InnerCollection.Count; }
    }

    public bool IsReadOnly
    {
        get { return ((ICollection<T>)this.InnerCollection).IsReadOnly; }
    }

    public IEnumerator<T> GetEnumerator()
    {
        return InnerCollection.GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return InnerCollection.GetEnumerator();
    }

}

鉴于该基类,我们可以通过两种方式使用它。示例是使用原始的 post 对象。

1)创建特定类型的包装集合(例如,List) 公共类 WrappedListCollection :WrappedCollectionBase、IList { 私有列表innerList;

    public WrappedListCollection(Action<T> addItemFunction, Func<T, bool> removeItemFunction, Action clearFunction)
        : base(addItemFunction, removeItemFunction, clearFunction)
    { 
    this.innerList = new List<T>();
    }

    protected override ICollection<T> GetWrappedCollection()
    {
        return this.innerList;
    }
 <...snip....> // fill in implementation of IList if important or don't implement IList
    }

然后可以使用:

 public Customer Customer
 {
 public ICollection<Order> Orders {get { return _orders; } }
 // Public methods.

 public void AddOrder(Order order)
 {
    _orders.AddToInnerCollection(order);
 }

// Private fields.

private WrappedListCollection<Order> _orders = new WrappedListCollection<Order>(this.AddOrder, null, null);
}

2)给出一个要包装的集合

 public class WrappedCollection<T> : WrappedCollectionBase<T>
{
    private ICollection<T> wrappedCollection;

    public WrappedCollection(ICollection<T> collectionToWrap, Action<T> addItemFunction, Func<T, bool> removeItemFunction, Action clearFunction)
        : base(addItemFunction, removeItemFunction, clearFunction)
    {
        this.wrappedCollection = collectionToWrap;
    }

    protected override ICollection<T> GetWrappedCollection()
    {
        return this.wrappedCollection;
    }
}

可以如下使用:

{ 公共 ICollection 订单 {get { return _wrappedOrders; } } // 公共方法。

 public void AddOrder(Order order)
 {
    _orders.Add(order);
 }

// Private fields.
private ICollection<Order> _orders = new List<Order>();
private WrappedCollection<Order> _wrappedOrders = new WrappedCollection<Order>(_orders, this.AddOrder, null, null);
}

还有一些其他方法可以调用WrappedCollection构造函数 例如,要覆盖添加但保持删除和清除正常

private WrappedListCollection<Order> _orders = new WrappedListCollection(this.AddOrder,  (Order o) => _orders.RemoveFromInnerCollection(o), () => _orders.ClearInnerCollection());

我同意如果 EF 不要求集合公开是最好的,但此解决方案允许我控制集合的修改。

对于阻止访问集合进行查询的问题,可以使用上面的方法2)并设置WrappedCollectionGetEnumerator方法抛出一个NotSupportedException。那么你的GetOrder方法可以保持原样。然而,更简洁的方法可能是公开包装的集合。例如:

 public class WrappedCollection<T> : WrappedCollectionBase<T>
 {
    public ICollection<T> InnerCollection { get; private set; }

    public WrappedCollection(ICollection<T> collectionToWrap, Action<T> addItemFunction, Func<T, bool> removeItemFunction, Action clearFunction)
        : base(addItemFunction, removeItemFunction, clearFunction)
    {
        this.InnerCollection = collectionToWrap;
    }


    protected  override ICollection<T> GetWrappedCollection()
    {
        return this.InnerCollection;
    }
}

然后调用GetOrder方法将变成

_orders.InnerCollection.Where(x => x.Id == id).Single();
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

当我在纯 EF4 代码中具有一对多映射时,可以隐藏 ICollection 字段吗? 的相关文章

  • EF4如何在多对多关系中公开联接表

    假设我有以下表格 Essence EssenceSet 和 Essence2EssenceSet 其中 Essence2EssenceSet 仅保存前 2 个表的 ID 以形成 M M 关系 在 EF 中 由于 Essence2Essenc
  • 参考装配错误

    我已经实现了 RoleProvider 类 在那里我创建了位于另一个程序集中的 Domain 类对象 我的程序集具有对该程序集的引用 错误 3 类型 System Data Entity DbContext 是在 未引用的程序集 您必须添加
  • 将平面集合转换为层次集合的递归方法?

    我已经被这个问题困扰了几天 希望得到一些想法或帮助解决它 我有一个对象集合 public class Hierarchy public Hierarchy string iD string name int level string par
  • 脚手架 EntityFramework 6 无法将“System.Data.Entity.Core.Objects.ObjectContext”类型的对象强制转换为“System.Data.Objects.ObjectContext”

    我想在 EntityFrameWork 6 中使用脚手架 但是得到这个 无法检索 myNameSpace Models prod 的元数据 无法将 System Data Entity Core Objects ObjectContext
  • 实体框架中的实体图是什么?

    我一直在研究一些实体框架教程 并且遇到了这个词实体图 我对这个术语及其用法还没有清楚的了解 任何人都可以提供有关此主题的信息 例如它是什么及其在实体框架上下文中的用途 当实例化的对象以某种关系连接在一起时 它们被称为 图或实体图 实体框架有
  • 实体框架:无需映射即可调用存储过程

    有没有一种方法可以在不使用实体框架函数映射的情况下使用存储过程 这很好 但是当向存储过程添加任何更改时 这完全是垃圾 我知道您可以刷新存储过程映射 但事实并非如此高效的 大多数时候 当您更新映射时 它不会检测到更改 这是非常烦人的 到目前为
  • 提供者未返回 ProviderManifest 实例

    当我想配置我的数据源 EntityDataSource 1 并将实体数据模型自动生成的连接字符串分配给它时 我收到错误 无法加载连接字符串中指定的元数据 请考虑重建 Web 项目以构建可能包含元数据的程序集 发生以下错误 提供程序未返回 P
  • C# 中处理 SQL 死锁的模式?

    我正在用 C 编写一个访问 SQL Server 2005 数据库的应用程序 该应用程序是数据库密集型的 即使我尝试优化所有访问 设置适当的索引等 我预计迟早会遇到死锁 我知道为什么会发生数据库死锁 但我怀疑我能否在某个时候发布不发生死锁的
  • 我应该对 ObjectContext 使用 using 关键字吗?

    我在这个网站或 CodeProject 的某个地方读到 好的规则是 如果某个类已经实现了 IDisposable 接口 那么您应该使用 using 关键字 因为使用翻译成 MSIL 的关键字会尝试 最终阻止如下内容 try some log
  • 实体框架多表多对多

    我正在使用 EF4 1 Code First 并尝试创建一些需要链接表的多对多关系表 请参阅下面的一小段代码 class Event int EventId get set ICollection
  • 外键与独立关系 - Entity Framework 5 有改进吗?

    我读过了several http www ladislavmrnka com 2011 05 foreign key vs independent associations in ef 4 文章和问题 https stackoverflow
  • 实体框架上下文中的条件 WHERE 子句

    objRecord await context Persons Where tbl gt tbl DeletedFlag false ToListAsync 这是我得到的 EF 代码 它成功地从Person表在哪里DeletedFlag是假
  • ASP.NET MVC5:想要使用模型绑定更新集合中的多个项目

    所以我有一个用户对象的集合 它应该是可批量编辑的 同时编辑许多用户 我使用实体框架将用户输入保存到数据库中 控制器方法从表单获取的集合为 null 为什么 另外 BindAttribute 是否可以像我的代码中那样与集合一起使用 View
  • MySql + 实体框架 = 每个派生表必须有自己的别名

    我必须从我的 C 程序访问另一个开发人员的一些 MySql 视图 因此 经过一番搜索后 我决定使用实体框架 并使用这个问题中提到的驱动程序 将 MySQL 与实体框架结合使用 https stackoverflow com question
  • 如何自动将实体模型更改部署到数据库?

    目前我使用 Visual Studio 数据库项目 因此我可以一键将更改部署到数据库并将数据保留在数据库中 现在我希望能够在实体框架中创建模型并一键部署 所以我得到了从实体框架创建数据库的sql脚本 我可以运行此脚本来创建数据库 但我想将数
  • 重构:从自定义数据访问层切换到实体框架

    我是一名 NET 开发人员 作为重构项目的一部分 我有几个问题 我们的软件当前使用 Active Record 模式 数据对象和业务对象之间的一对一映射 不好的是业务对象继承自数据对象 导致层之间的高度耦合 我们的目标是从自定义数据访问层
  • C# Fluent API 将两个属性映射到同一列

    我的问题实际上很简单 这是MySQL表 俱乐部类别 正如您所看到的 它将俱乐部与类别链接起来 Field Type Null Key Default Extra CategoryId int NO PRI NULL ClubId int N
  • 无法将 null 值插入列...当值不为 null 时

    在我的 C 代码中 我在数据库中有一个插入 但它引发了异常 无法将 NULL 值插入表 Moroccanoil Replicated dbo Boxes 的 BoxID 列 列不允许为空 插入失败 然而 在调试这段代码时 我发现该框实际上不
  • 在 WebAPI OData 请求中包含相关实体

    有没有办法在 OData 请求中包含相关实体 例如 我有一个 Person 实体和一个 Task 实体 这种关系是一对多的 一个人有很多任务 如果我使用 OData 请求查询数据 odata Person 要获取所有 Person 实体 返
  • 类型“Queryable”上的通用方法“OrderBy”与提供的类型参数不兼容

    我正在编写一些代码来修改表达式 以便其中包含的子查询得到排序 我发现了一段类似的代码这里就这样 https stackoverflow com a 1379693 509464 但这对我不起作用 我也尝试看看this https stack

随机推荐