实体框架5 - 在从数据库加载实体后寻找执行自定义代码的中心点

Sam*_*tum 12 entity-framework entity-framework-5

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

我不希望在实体中包含任何WCF客户端逻辑.我更喜欢将此逻辑保存在存储库代码(DbContext,DbSet等)中.

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

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

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

提前致谢.

萨姆

Sam*_*tum 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);
                }
            }
        }    
    }
}
Run Code Online (Sandbox Code Playgroud)