0

我在 EF4.4 中有大约 12 个表,我需要从一个常见的用户查找表中加载 2 个属性(实际上执行了两次 - 一次用于 CreatedUser,一次用于 ModifiedUser)。

用户表有其他不为空的列,我尝试删除它们(以保存查询结果),EF 抱怨必须映射它们。有没有办法绕过这个错误,因为我不会插入到那个表中——只是将它用于选择。

好的是因为 FK,它已经是一个参考属性。如果我要将其更改为自定义视图,那么我必须手动重做所有 12 个视图并将它们链接到该表 - 这不是世界末日,但要尽量避免它:)

4

1 回答 1

0

Let me see if I understand this correctly. It sounds to me like you have a Users table defined something like this:

public class User
{
  //just assume that the following are all properties with {get;set;}
  public int ID
  public string Name
  public string Email
  public string Password
  public string Address
  //etc etc
}

Then you have other tables defined something like this:

public class SomeObject
{
  public int ID
  public string ObjectName
  public string Category
  //etc etc
  public virtual User CreatedUser
  public virtual User ModifiedUser
}

And the 2 properties you want to load are the Name and Email (or something like that) without loading the other values for the Password, Address and whatever else is there. Am I close?

I also don't know whether you are using Code-First or not, but that's what I'm assuming for the moment...(mostly because that's what I'm most familiar with)

It sounds like what you're wanting to do is add something like this:

public class SomeObject
{
  //all the other stuff here...
  public string CreatedUserName
  public string CreatedUserEmail
  public string ModifiedUserName
  public string ModifiedUserEmail
}

But what you should actually add is more like this:

[NotMapped]
public string CreatedUserName
{
  get { return CreatedUser.Name; }
}

This would make it so that EF is traversing the relationship to get to the User record and retrieve the Name value. The [NotMapped] attribute makes it so that EF knows that it shouldn't expect to find a CreatedUserName column on the SomeObjects table.

Does this answer your question? If not, please try to explain some more about what flavor of EF you are using and what you are trying to do with it. ;)

[Additional Info in response to OP's comment]

I would caution against trying to "cache a slim version of the User table and look up the other properties that way". That could be a case of premature optimization. In other words, you might think that you are making it work smoother by querying and caching the UserNames and Emails from the User table, but it might end up that you really are just making it work harder than it needs to.

I'm NOT saying that this is for certain in your case, just that you should really have a good idea of what EF is doing and what the needs of your program are before you try to optimize it. To do that, you should put it through some testing and see where your bottlenecks are. If for example network communication to the database is an expensive bottleneck, then adding additional caching of records might improve that. If on the other hand memory and CPU constraints are slowing it down, then caching would be a bad idea.

One other thing I would like to point out is that if this program is going to be running on a server that is relatively close to the database (on the same machine or on the same network), then making extra calls to the database shouldn't be much of a concern. If however this is a desktop application tunneling across the internet to get to a single database server that is connected to the internet through a T1 connection (for example) then calls to the database are probably going to be a huge concern. Again, I'm not saying that any of these cases are true in your situation, just that they need to be examined before you decide to implement additional caching on top of the caching that EF already does on its own.

All that being said, let me offer another suggestion that might work for you. If you are only interested in getting the UserName and Email of several objects at a time and aren't really doing anything else with the objects at that moment (for instance, outputting a list of objects in an ASP.NET MVC Index view), I would suggest either using Include to eager-load the related User records in your query like this:

var query = MyDbContext.SomeObjects.Where(x => x.Category == "Foo")
  .Include(x => x.CreatedUser)
  .Include(x => x.ModifiedUser);

...or defining queries that only select the fields you want into an anonymous class like this:

var query = MyDbContext.SomeObjects.Where(x => x.Category == "Foo")
  .Select(x => new {
    ObjectName = x.ObjectName,
    CreatedUserName = x.CreatedUser.Name,
    CreatedUserEmail = x.CreatedUser.Email,
    ModifiedUserName = x.ModifiedUser.Name,
    ModifiedUserEmail = x.ModifiedUser.Email 
  });

The first option benefits from using EF's already built in object caching mechanisms and from executing a single select statement to fetch all of the records that you need without fetching unrelated User records that you don't need. The second option benefits from also being a single select statement that fetches only the things you need and further reduces the returned data by filtering out columns you aren't interested in. But it wouldn't benefit from EF's object caching mechanisms (at least I don't think it would).

If on the other hand you are doing multiple things with the objects or are only getting the related UserName and Email from one or two (or a relative few) objects at a time, I would suggest relying on the navigation properties and maybe doing something similar to what I demonstrated earlier.

于 2013-07-03T21:06:06.747 回答