繁体   English   中英

当两个表中都不存在ID时,使用Linq连接实体框架表

[英]Joining Entity Framework tables using Linq when IDs do not exist in both tables

以下是我使用实体框架在数据库中生成表的类。 我希望能够将此表链接到另一个表Property 但是,我的代码设置方式是在Instruction表中没有Id列,在类中没有Property属性,然后在实际数据库中生成了PropertyId列,但是由于Property属性不是Id I我无法使用Linq联接这些表。

指令表

[Table("Instruction")]
public class Instruction
    {
        [Key]
        public int Id { get; set; }
        public InstructionTypes InstructionType { get; set; }
        public Property Property { get; set; } //Generates the EF property FK, but is not an ID so therefore cannot be used in linq.
    }

属性表

[Table("Property")]
    public partial class Property
    {
        [Key]
        public int Id { get; set; }
        public Address Correspondence { get; set; }
    }

联接查询

var instruction = 
                from instructions in _context.Instructions
                join properties in _context.Properties on instructions.Property equals properties.Id
                where ...

上面的查询给出了一个编译器错误:`join子句中的表达式之一的类型不正确。

当我尝试使用属性对象与propertyId联接时,正在生成此错误。

如何更改此查询,以便能够联接这两个表?

您似乎是linq的新手。 因此,您仍在思考,好像您仍在sql世界中一样。

对于linq to实体,使用join是一个例外。 EF使用导航属性以静默方式生成SQL join

因此,您的查询可以是:

var instruction = 
            from instruction in _context.Instructions                
            where instruction.Porperty.Correspondence.Contains("abc");

然后您可以访问

instruction.First().Property.Correspondence

作为一种好习惯,您可以将外键声明为类成员,并使用流畅的API绑定它们。

要测试您可以使用以下代码,

//assuming that Instructions is a DbSet<Instruction>
using (var context = new MyContext() ) {
    context.Instructions.Add(
        new instruction {
            Property = new Property {
                Correspondence = new Address {}
            }
        });
}

using (var context = new MyContext() ) {
    var c = context.Instructions.First();
    console.WriteLine($"{c.Id}, {c?.Property.Id}, {c?.Property?.Correspondence.Id}");
});

在所有情况的99%中,您都不希望使用join运算符。 使用导航属性时,Entity Framework会自动为您生成SQL JOINS。

var instruction = await _context.Instructions.Where(i => i.Property...).FirstOrDefaultAsync().ConfigureAwait(false);

请注意,根据您使用的是EF6还是EF Core或不同的配置,可能会禁用“延迟加载”(如果没有,则强烈建议您禁用它,因为这是一个巨大的性能瓶颈)。

因此,您必须使用Include方法来热切加载相关实体。

var instruction = await _context.Instructions.Include(i => i.Property).Where(i => i.Property...).FirstOrDefaultAsync().ConfigureAwait(false);

但是在执行此操作之前,请先考虑一下是否确实需要该Instruction 如果没有,您的代码可能变成:

var property = await _context.Properties.Where(p => p.Instructions.Any(i => ...)).FirstOrDefaultAsync().ConfigureAwait(false);

请注意,您必须扩展Property类才能使其具有向后引用

public partial class Property
{
    // No need for the Key attribute, as this is convention
    public int Id { get; set; }
    public Address Correspondence { get; set; }
    public int CorrespondenceId { get; set; } // Not needed in this scenario, but good practice
    public ICollection<Instruction> Instructions { get; } = new HashSet<Instruction>();
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM