针对没有关系的EF上下文创建LINQ语句

时间:2015-07-28 21:31:40

标签: c# linq entity-framework

我无法解决如何针对我的EF上下文编写linq查询以获得我想要的内容。

1)我拥有什么 没有分配外键的数据库,以及反向工程代码第一实体框架项目。我尝试手动添加虚拟类,因此EF可能会在DBcontext中创建隐含的外键,但我的.Include语句仍然出现错误。

没有包含我唯一能想到的就是使用左连接,但我还没有把它弄下来。最后我将有21个表来获取数据,但下表概述了我面临的大多数问题。

示例数据结构:

Table Human :HumanId,LastFoodEatenId,FavoriteFoodId,CurrentlyDesiredFoodId

餐食:FoodId,FoodName,FoodStuff

桌上玩具:HumanOwnerId,ToyId,ToyName

表宠物:HumanOwnerId,PetId,PetName,PetType

Table PetSurgery :PetId,SurgeryId,SurgeryPerformed

2)我想要什么 给定一个HumanID,我想从一个查询中获得一个compsite类或类似的东西。

Public Class QueryResult
{
  public Human human {get;set;}
  public Food LastEatenFood {get;set;}
  public Food FavoriteFood {get;set;}
  public Food CurrentlyDesiredFood {get;set;}
  public IEnumerable<Toy> Toys {get;set;}
  public IEnumerable<Pet> Pets {get;set;} //Includes surgeries if any
}

是否可以编写单个查询以在单个数据库命中中获取此类信息?我很好,有人只是确认这是不可能的。然后我至少可以请求我们添加与数据库的关系。

提前致谢,

2 个答案:

答案 0 :(得分:1)

您可以使用linq查询多个不相关的表。

我会假设你的实体很多,但我们走了......

int humanId = 1234;

using (var context = new MyContext())
{
    var human = (from h in context.Humans
                 join lf in context.Foods on h.LastFoodEatenId equals lf.foodId into lfg
                 from lf in lfg.DefaultIfEmpty() // left join
                 join ff in context.Foods on h.FavoriteFoodId equals lf.foodId into ffg
                 from ff in ffg.DefaultIfEmpty() // left join
                 join cf in context.Foods on h.CurrentlyDesiredFoodId equals lf.foodId into cfg
                 from cf in cfg.DefaultIfEmpty() // left join
                 join p in context.Pets on h.humanId equals p.humanId into pg // group
                 join t in context.Toys on h.humanId equals t.humanId into tg // group
                 where h.humanId = humanId
                 select new QueryResult { human = h, LastEatenFood = lf, FavoriteFood = ff, CurrentlyDesiredFood = cf, Toys = tg, Pets = pg }
                 ).SingleOrDefault();
}

注意:我没有使用语法检查程序从内存中执行此操作,因此ymmv。也应该可以添加手术,但可能需要子查询。

答案 1 :(得分:1)

  

我尝试手动添加虚拟类

我认为你的意思是虚拟集合。如果它们不在数据库中,您可以在“代码优先”模型中定义关系。唯一的条件是外键必须引用EF知道作为主键的属性。所以你应该能够使用导航属性进行LINQ查询,而不是通过这样的模型进行这些详细的连接(简化为基本要素):

class Human
{
    public int HumanId { get; set; }

    public int LastFoodEatenId { get; set; }
    public virtual Food LastEatenFood { get; set; }

    public int FavoriteFoodId { get; set; }
    public virtual Food FavoriteFood { get; set; }

    public int CurrentlyDesiredFoodId { get; set; }
    public virtual Food CurrentlyDesiredFood { get; set; }

    public virtual ICollection<Toy> Toys { get; set; }
    public virtual ICollection<Pet> Pets { get; set; }
}

class Food
{
    public int FoodId { get; set; }
}

class Pet
{
    public int PetId { get; set; }
    public int HumanOwnerId { get; set; }
}

class Toy
{
    public int ToyId { get; set; }
    public int HumanOwnerId { get; set; }
}

和映射:

class HumanMapping : EntityTypeConfiguration<Human>
{
    public HumanMapping()
    {
        HasOptional(h => h.LastEatenFood).WithMany()
            .HasForeignKey(h => h.LastFoodEatenId);
        HasOptional(h => h.FavoriteFood).WithMany()
            .HasForeignKey(h => h.FavoriteFoodId);
        HasOptional(h => h.CurrentlyDesiredFood).WithMany()
            .HasForeignKey(h => h.CurrentlyDesiredFoodId);
        HasMany(h => h.Toys).WithOptional().HasForeignKey(t => t.HumanOwnerId);
        HasMany(h => h.Pets).WithOptional().HasForeignKey(t => t.HumanOwnerId);
    }
}

EF将按名称约定推断主键。

现在您将能够执行LINQ语句,如:

context.Humans.Where(h => h.HumanId == id)
       .Include(h => h.LastEatenFood)
       .Include(h => h.FavoriteFood)
       .Include(h => h.CurrentlyDesiredFood)
       .Include(h => h.Toys)
       .Include(h => h.Pets)

根据您的说明,我了解PetSurgery应该是Pet与另一个类Surgery之间的联结类?)。无论如何,我认为你将管理创建正确的映射,看看这个例子。