简体   繁体   English

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

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

Below is a class I have used to generate a table in my database using Entity Framework. 以下是我使用实体框架在数据库中生成表的类。 I'd like to be able to link this table to another table, Property . 我希望能够将此表链接到另一个表Property However, the way my code is set up there is not an Id column in the Instruction table, there is a Property property within the class, which then generates a PropertyId column in the actual database, but since the Property property is not an Id I am unable to using Linq to join these tables. 但是,我的代码设置方式是在Instruction表中没有Id列,在类中没有Property属性,然后在实际数据库中生成了PropertyId列,但是由于Property属性不是Id I我无法使用Linq联接这些表。

Instruction table 指令表

[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.
    }

Property table 属性表

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

Join Query 联接查询

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

The above query gives a compiler error of: `The type of one of the expressions in the join clause is incorrect. 上面的查询给出了一个编译器错误:`join子句中的表达式之一的类型不正确。

This error is being generated as I'm attempting to use a property object to join with a propertyId. 当我尝试使用属性对象与propertyId联接时,正在生成此错误。

How can I alter this query so that I am able to join these two tables? 如何更改此查询,以便能够联接这两个表?

You seems to be a newcomer to linq. 您似乎是linq的新手。 As such you are still thinking as if you still are in an sql world. 因此,您仍在思考,好像您仍在sql世界中一样。

With linq to entities, the use of join is the exception. 对于linq to实体,使用join是一个例外。 SQL join are generated silently by EF using the navigation properties. EF使用导航属性以静默方式生成SQL join

So your query can be: 因此,您的查询可以是:

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

then you can access 然后您可以访问

instruction.First().Property.Correspondence

As a good practice you can delclare the foreign keys as class members and use the fluent API to bind them. 作为一种好习惯,您可以将外键声明为类成员,并使用流畅的API绑定它们。

To test you can use the following code, 要测试您可以使用以下代码,

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

In 99% of all cases, you do not want to use the join operator. 在所有情况的99%中,您都不希望使用join运算符。 Entity Framework automatically generates SQL JOINS for you when you are using Navigation Properties. 使用导航属性时,Entity Framework会自动为您生成SQL JOINS。

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

Note, that depending on whether you are using EF6 or EF Core or with different configuration, Lazy Loading may be disabled (if not, I strongly encourage you to disable it as it is a massive performance bottleneck). 请注意,根据您使用的是EF6还是EF Core或不同的配置,可能会禁用“延迟加载”(如果没有,则强烈建议您禁用它,因为这是一个巨大的性能瓶颈)。

So you have to use the Include Method to eagerly load the related entity. 因此,您必须使用Include方法来热切加载相关实体。

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

But before doing this, think if you really need the Instruction . 但是在执行此操作之前,请先考虑一下是否确实需要该Instruction If not, your code could become: 如果没有,您的代码可能变成:

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

Please note that you have to extend your Property class for this to work to have a back-reference 请注意,您必须扩展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