C# - 实体框架 - 了解一些基础知识

时间:2010-01-20 22:15:30

标签: c# .net entity-framework models

Model#1 - 该模型位于Dev Server的数据库中。 Model #1 http://content.screencast.com/users/Keith.Barrows/folders/Jing/media/bdb2b000-6e60-4af0-a7a1-2bb6b05d8bc1/Model1.png

模型#2 - 该模型位于我们的Prod服务器上的数据库中,并且每天通过自动提要进行更新。 alt text http://content.screencast.com/users/Keith.Barrows/folders/Jing/media/4260259f-bce6-43d5-9d2a-017bd9a980d4/Model2.png

我已经编写了一些简单的代码来将我的Feed(Model#2)同步到我的工作DB(Model#1)中。请注意这是原型代码,模型可能不如它们应该的那么漂亮。此外,进入链接数据(主要是ClientID)的模型#1是一个手动过程,这就是我编写这个简单同步方法的原因。

private void SyncFeeds()
{
    var sourceList = from a in _dbFeed.Auto where a.Active == true select a;
    foreach (RivWorks.Model.NegotiationAutos.Auto source in sourceList)
    {
        var targetList = from a in _dbRiv.Product where a.alternateProductID == source.AutoID select a;
        if (targetList.Count() > 0)
        {
            // UPDATE...
            try
            {
                var product = targetList.First();
                product.alternateProductID = source.AutoID;
                product.isFromFeed = true;
                product.isDeleted = false;
                product.SKU = source.StockNumber;
                _dbRiv.SaveChanges();
            }
            catch (Exception ex)
            {
                string m = ex.Message;
            }
        }
        else
        {
            // INSERT...
            try
            {
                long clientID = source.Client.ClientID;
                var companyDetail = (from a in _dbRiv.AutoNegotiationDetails where a.ClientID == clientID select a).First();
                var company = companyDetail.Company;
                switch (companyDetail.FeedSourceTable.ToUpper())
                {
                    case "AUTO":
                        var product = new RivWorks.Model.Negotiation.Product();
                        product.alternateProductID = source.AutoID;
                        product.isFromFeed = true;
                        product.isDeleted = false;
                        product.SKU = source.StockNumber;
                        company.Product.Add(product);
                        break;
                }
                _dbRiv.SaveChanges();
            }
            catch (Exception ex)
            {
                string m = ex.Message;
            }
        }
    }
}

现在提出问题:

  1. 在Model#2中,Auto的类结构缺少ClientID(参见红色圆圈区域)。现在,我学到的一切,EF创建了一个Client类的子类,我应该能够在子类中找到ClientID。然而,当我运行我的代码时,source.Client是一个NULL对象。我是否期待EF不做的事情?有没有办法正确填充子类?
  2. 为什么EF会隐藏父表中的子实体ID(本例中为ClientID)?有没有办法揭露它?
  3. 还有什么像谚语疮拇指一样突出?
  4. TIA

1 个答案:

答案 0 :(得分:2)

1)您看到null source.Client的原因是因为相关对象在您请求它们之前未加载,或者它们被加载到对象上下文中。以下将明确加载它们:

if (!source.ClientReference.IsLoaded)
{
    source.ClientReference.Load();
}

但是,当您拥有多个记录的列表时,这是次优的,因为它会根据Load()调用发送一个数据库查询。更好的选择是初始查询中的Include()方法,以指示ORM加载您感兴趣的相关实体,因此:

var sourceList = from a in _dbFeed.Auto .Include("Client") where a.Active == true select a;

另一种第三种方法是使用某种调用关系修复方法,例如,如果在您的示例中,之前已查询过相关客户端,则它们仍将位于您的对象上下文中。例如:

var clients = (from a in _dbFeed.Client select a).ToList();

然后,EF将“修复”关系,因此source.Client不会是null。显然,如果您需要所有客户端的列表进行同步,这只是您要做的事情,因此与您的具体示例无关。

永远记住,除非您提出要求,否则永远不会将对象加载到EF中!

2) EF的第一个版本故意不将外键字段映射到可观察的字段或属性。 This对此事是一个很好的破坏。在EF4.0中,我了解外键会因受欢迎的需求而暴露出来。

3)您可能遇到的一个问题是请求Products或AutoNegotiationContacts可能生成的数据库查询数。作为替代方案,请考虑批量加载它们或在初始查询中使用join

将对象上下文用于一个“操作”,然后处理它,而不是将它们跨请求持久化也被视为一种良好的做法。初始化一个开销非常小,因此每个SychFeeds()一个对象上下文更合适。 ObjectContext实现IDisposable,因此您可以在using块中对其进行实例化,并将方法的内容包装在其中,以确保在提交更改后所有内容都得到正确清理。