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

时间:2018-10-16 12:56:35

标签: c# entity-framework linq

以下是我使用实体框架在数据库中生成表的类。我希望能够将此表链接到另一个表Property。但是,我的代码的设置方式是Instruction表中没有Id列,类中有Property属性,然后在实际数据库中生成了PropertyId列,但是由于Property属性是不是Id,我无法使用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联接时,正在生成此错误。

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

2 个答案:

答案 0 :(得分:0)

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

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

因此您的查询可以是:

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}");
});

答案 1 :(得分:0)

在所有情况的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>();
}