3

模型 #1 - 该模型位于我们开发服务器上的数据库中。 模型 #1 http://content.screencast.com/users/Keith.Barrows/folders/Jing/media/bdb2b000-6e60-4af0-a7a1-2bb6b05d8bc1/Model1.png

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

我已经编写了一些简单的代码来将我的提要(模型#2)同步到我的工作数据库(模型#1)中。请注意,这是原型代码,模型可能没有应有的漂亮。此外,Feed 链接数据(主要是 ClientID)进入 Model #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. 在模型 #2 中,Auto 的类结构缺少 ClientID(见红圈区域)。现在,我所学到的一切,EF 创建了一个 Client 的子类,我应该能够在子类中找到 ClientID。然而,当我运行我的代码时, source.Client 是一个 NULL 对象。我是否期待 EF 不会做的事情?有没有办法正确填充子类?
  2. 为什么EF在父表中隐藏子实体ID(本例中为ClientID)?有什么办法可以暴露吗?
  3. 还有什么像众所周知的拇指酸痛一样突出?

TIA

4

1 回答 1

3

1) The reason you are seeing a null for source.Client is because related objects are not loaded until you request them, or they are otherwise loaded into the object context. The following will load them explicitly:

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

However, this is sub-optimal when you have a list of more than one record, as it sends one database query per Load() call. A better alternative is to the Include() method in your initial query, to instruct the ORM to load the related entities you are interested in, so:

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

An alternative third method is to use something call relationship fix-up, where if, in your example for instance, the related clients had been queried previously, they would still be in your object context. For example:

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

The EF will then 'fix-up' the relationships so source.Client would not be null. Obviously this is only something you would do if you required a list of all clients for synching, so is not relevant for your specific example.

Always remember that objects are never loaded into the EF unless you request them!

2) The first version of the EF deliberately does not map foreign key fields to observable fields or properties. This is a good rundown on the matter. In EF4.0, I understand foreign keys will be exposed due to popular demand.

3) One issue you may run into is the number of database queries requesting Products or AutoNegotiationContacts may generate. As an alternative, consider loading them in bulk or with a join on your initial query.

It's also seen as good practice to use an object context for one 'operation', then dispose of it, rather than persisting them across requests. There is very little overhead in initialising one, so one object context per SychFeeds() is more appropriate. ObjectContext implements IDisposable, so you can instantiate it in a using block and wrap the method's contents in that, to ensure everything is cleaned up correctly once your changes are submitted.

于 2010-01-20T22:48:38.877 回答