12

我正在使用 Entity Framework 5 和 Code First 方法,并使用 Fluent API 进行实体配置。我的项目有一个特定的产品实体,它的一半数据来自数据库,另一半来自通过 WCF 客户端检索的数据合同(它是用于管理产品库存的第 3 方系统)。Data Contract 是 Product Entity 类的成员(我还没有决定的属性或方法)。

我不希望实体中包含任何 WCF 客户端逻辑。我更愿意将此逻辑保留在存储库代码(DbContext、DbSet 等)中。

那么在从数据库中检索到产品实体之后,是否有一种技术可以连接到实体框架(或拦截)?我应该注意到产品实体作为导航属性出现在其他实体上。如果挂钩或拦截是可能的,那么这意味着我可以在 EF 从数据库加载产品实体后立即从 SOAP 服务检索数据协定。我的项目的好处是 WCF 客户端检索代码不需要在整个应用程序中重复。

我的一个想法是为 Data Contract 实现 IDbSet,而 IDbSet 将负责检索它。然后以某种方式欺骗 EF 认为它是产品实体上的导航属性。但我不确定数据库 DbSet 是否可以在同一个 DbContext 中与非数据库 IDbSet 混合。还有另一个问题 - EF 如何知道从 IDbSet 植入中检索导航属性?在投入时间之前,我想知道这个想法是否可行。我也想知道从哪里开始寻找。

请注意,我使用 .NET 已经超过 10 年了,但是这个 EF5 的东西对我来说还是比较新的。

提前致谢。

-山姆

4

2 回答 2

20

今天我在实体框架中发现了一个似乎是我正在寻找的事件。ObjectContext.ObjectMaterialized 事件。显然,DbContext 实现了 IObjectContextAdapter,而后者又公开了 ObjectContext。从那里我可以订阅 ObjectMaterialized 事件。

MSDN 读取:在作为查询或加载操作的一部分从数据源中的数据创建新实体对象时发生。

下面的代码演示了我如何使用 ObjectMaterialized 事件来解决我的问题,其中我的一个偏好是有一个中心点来放置 WCF 客户端访问逻辑。

// seperate assembly - does not use Domain.Repositories assembly
namespace Domain.Models
{
    // the data contract
    [DataContract]
    public class ProductInventoryState
    {
        [DataMember]
        public int StockStatus { get; set; }

        [DataMember]
        public IEnumerable<String> SerialNumbers { get; set; }

        // etc....
    }

    // the entity
    public class Product
    {
        public Guid Key { get; set; }
        public string ProductCode { get; set; }
        public ProductInventoryState InventoryState { get; set; }
        // etc....
    }
}

// seperate assembly - uses Domain.Models assembly
namespace Domain.Repositories
{
    public class MainRepository : DbContext
    {
        public MainRepository()
        {
            ((IObjectContextAdapter)this).ObjectContext.ObjectMaterialized += ObjectContext_ObjectMaterialized;
        }

        protected void ObjectContext_ObjectMaterialized(object sender, ObjectMaterializedEventArgs e)
        {
            if (e.Entity == null)
                return;

            if (e.Entity is Product)
            {
                Product product = (Product)e.Entity;

                // retrieve ProductInventoryState from 3rd party SOAP API
                using (ThirdPartyInventorySystemClient client = new ThirdPartyInventorySystemClient())
                {
                    // use ProductCode to retrieve the data contract
                    product.InventoryState = client.GetInventoryState(product.ProductCode);
                }
            }
        }    
    }
}
于 2013-02-07T00:06:33.200 回答
1

1.)您可以编写自己的 EF 提供程序(但这不是一项小任务)

2.) 您可以将项目附加到上下文但不能保存它们。

entity.State 可以设置为附加后不修改。您还可以在保存更改之前从上下文中删除此类条目

3)您可以编写一个存储库门面,检查 EF 并检查位置 2 并组合结果。

关于导航属性的问题。您需要非常仔细地指定这些以避免出现问题。没有延迟加载,甚至没有建模。

我不会尝试亲自混合它们。
您可以告诉 EF 忽略某些属性。因此,您可以拥有一个不错的原始 POCO,但仅对数据库上的位进行建模。

然后 POCO 将收集其余部分。

我自己使用带有事件的门面来作用于上下文/DBset 上的 KEY 方法。所以我可以触发附加、获取、保存等事件。

祝你好运

于 2013-02-05T17:10:34.943 回答