如何在 linq 中编写此 C# 语句
How to write this C# statement in linq
我正在尝试将相关表 Adress 和 PlzOrt 放入对象 User 中。
关系如下:
用户1:1地址
地址 n:1 PlzOrt
从数据库搭建的实体
public partial class User
{
//No hash sets for Adress Scaffolded (probably unnecessary since the is
//only ever one address per user
public int IdUser { get; set; }
public int? FidAdresse { get; set; }
public string Email { get; set; }
public string Vorname { get; set; }
public string Nachmname { get; set; }
[ForeignKey("FidAdresse")]
[InverseProperty("User")]
public virtual Adresse FidAdresseNavigation { get; set; }
}
public partial class Adresse
{
public Adresse()
{
User = new HashSet<User>();
}
public int IdAdresse { get; set; }
public int FidPlzOrt { get; set; }
public string Strasse { get; set; }
public string Hausnr { get; set; }
[ForeignKey("FidPlzOrt")]
[InverseProperty("Adresse")]
public virtual PlzOrt FidPlzOrtNavigation { get; set; }
[InverseProperty("FidAdresseNavigation")]
public virtual ICollection<User> User { get; set; }
}
public partial class PlzOrt
{
public PlzOrt()
{
Adresse = new HashSet<Adresse>();
}
public int IdPlzOrt { get; set; }
public string Plz { get; set; }
public string Ort { get; set; }
[InverseProperty("FidPlzOrtNavigation")]
public virtual ICollection<Adresse> Adresse { get; set; }
}
这是不起作用的 linq。
return _context.User
.Include(u => u.FidPermissionNavigation)
.Include(c => c.FidAdresseNavigation)
.ThenInclude(c => c.FidPlzOrtNavigation)
.FirstOrDefault(c => c.IdUser == id);
当我不包含 "ThenInclude(c => c.FidPlzOrtNavigation)" 语句时,linq 工作,但我希望在我的对象中包含此信息。
这是给我预期结果的 C#:
public User GetUser(int id)
{
foreach (User user in _context.User)
{
if (user.IdUser == id)
{
foreach (Adresse adresse in _context.Adresse)
{
if (adresse.IdAdresse == user.FidAdresse)
{
user.FidAdresseNavigation = adresse;
foreach (PlzOrt plzOrt in _context.PlzOrt)
{
if (plzOrt.IdPlzOrt == adresse.FidPlzOrt)
{
user.FidAdresseNavigation.FidPlzOrtNavigation = plzOrt;
break;
}
}
break;
}
}
return user;
}
}
return null;
}
翻译这条 linq 语句会有很大帮助。提前致谢。
已生成 db_context 代码以供您感兴趣或有帮助
modelBuilder.Entity<User>(entity =>
{
entity.HasKey(e => e.IdUser)
.HasName("PRIMARY");
entity.HasIndex(e => e.FidAdresse)
.HasName("fk_User_Adresse1_idx");
entity.HasOne(d => d.FidAdresseNavigation)
.WithMany(p => p.User)
.HasForeignKey(d => d.FidAdresse)
.HasConstraintName("fk_User_Adresse1");
});
modelBuilder.Entity<Adresse>(entity =>
{
entity.HasKey(e => e.IdAdresse)
.HasName("PRIMARY");
entity.HasIndex(e => e.FidPlzOrt)
.HasName("fk_Adresse_plz_ort1_idx");
entity.HasOne(d => d.FidPlzOrtNavigation)
.WithMany(p => p.Adresse)
.HasForeignKey(d => d.FidPlzOrt)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("fk_Adresse_plz_ort1");
});
modelBuilder.Entity<PlzOrt>(entity =>
{
entity.HasKey(e => e.IdPlzOrt)
.HasName("PRIMARY");
});
所以您有一个 id
,并且您想要唯一一个将此 ID 作为主键的用户,以及他的地址和他的 PlzOrt。
Whenever you query, use Select to fetch the data. Only use Include if you want to update the fetched data.
Select 的原因是你有更大的自由select。此外,您可以限制获取的数据:如果您查询学校及其学生,您知道学校 10 的每个学生都有一个等于 10 的外键 SchoolId。那么为什么要为每个学校 1000 个学生获取这个外键?
我不熟悉 ef-core 的可能性。它知道如果您 Select 需要(组)加入的虚拟属性之一吗?在这种情况下,使用 Select.
更容易
如果您必须自己进行连接:
var requestedUserWithAddresAndPlz = dbContext.Users.
// keep only the user with id
.Where(user => user.IdUser == id)
// every User has exactly one Address: use a normal join
.Join(dbContext.Addresses,
user => user.IdUser, // from every User take IdUser
address => addres.IdAddress, // from every Address take IdAddress
// result selector: take the user with its address to make one new
(user, address) => new
{
// Select only the User properties you plan to use
Id = user.IdUser,
Name = user.Name,
...
Address = new
{
// again: select only the properties you plan to use
// no need to select IdAddress, you know the value!
Street = address.Street,
HouseNumber = address.HouseNumber,
// to fetch the Plz: fetch the one-and-only PlzOrt with address.FidPlzOrt
Plz = dbContext.PlzOrts
.Where(plzOrt => plzOrt.PlzOrdIt == address.FidPlzOrt)
.FirstOrDefault(),
})
.FirstOrDefault();
注意:我使用匿名类型是为了在 select 只使用我实际计划使用的属性方面有更大的自由度。我也可以给我的属性起我想要的名字。
缺点:不能将匿名类型用作 return 值。如果您确实需要在您的函数之外使用它,请使用创建一个包含您的数据的 class,并使用 new SomeClass()。优点:如果你的数据库发生变化,SomeClass 不必改变,因此你的调用者不会注意到你的数据库中的变化。
我正在尝试将相关表 Adress 和 PlzOrt 放入对象 User 中。 关系如下:
用户1:1地址
地址 n:1 PlzOrt
从数据库搭建的实体
public partial class User
{
//No hash sets for Adress Scaffolded (probably unnecessary since the is
//only ever one address per user
public int IdUser { get; set; }
public int? FidAdresse { get; set; }
public string Email { get; set; }
public string Vorname { get; set; }
public string Nachmname { get; set; }
[ForeignKey("FidAdresse")]
[InverseProperty("User")]
public virtual Adresse FidAdresseNavigation { get; set; }
}
public partial class Adresse
{
public Adresse()
{
User = new HashSet<User>();
}
public int IdAdresse { get; set; }
public int FidPlzOrt { get; set; }
public string Strasse { get; set; }
public string Hausnr { get; set; }
[ForeignKey("FidPlzOrt")]
[InverseProperty("Adresse")]
public virtual PlzOrt FidPlzOrtNavigation { get; set; }
[InverseProperty("FidAdresseNavigation")]
public virtual ICollection<User> User { get; set; }
}
public partial class PlzOrt
{
public PlzOrt()
{
Adresse = new HashSet<Adresse>();
}
public int IdPlzOrt { get; set; }
public string Plz { get; set; }
public string Ort { get; set; }
[InverseProperty("FidPlzOrtNavigation")]
public virtual ICollection<Adresse> Adresse { get; set; }
}
这是不起作用的 linq。
return _context.User
.Include(u => u.FidPermissionNavigation)
.Include(c => c.FidAdresseNavigation)
.ThenInclude(c => c.FidPlzOrtNavigation)
.FirstOrDefault(c => c.IdUser == id);
当我不包含 "ThenInclude(c => c.FidPlzOrtNavigation)" 语句时,linq 工作,但我希望在我的对象中包含此信息。
这是给我预期结果的 C#:
public User GetUser(int id)
{
foreach (User user in _context.User)
{
if (user.IdUser == id)
{
foreach (Adresse adresse in _context.Adresse)
{
if (adresse.IdAdresse == user.FidAdresse)
{
user.FidAdresseNavigation = adresse;
foreach (PlzOrt plzOrt in _context.PlzOrt)
{
if (plzOrt.IdPlzOrt == adresse.FidPlzOrt)
{
user.FidAdresseNavigation.FidPlzOrtNavigation = plzOrt;
break;
}
}
break;
}
}
return user;
}
}
return null;
}
翻译这条 linq 语句会有很大帮助。提前致谢。
已生成 db_context 代码以供您感兴趣或有帮助
modelBuilder.Entity<User>(entity =>
{
entity.HasKey(e => e.IdUser)
.HasName("PRIMARY");
entity.HasIndex(e => e.FidAdresse)
.HasName("fk_User_Adresse1_idx");
entity.HasOne(d => d.FidAdresseNavigation)
.WithMany(p => p.User)
.HasForeignKey(d => d.FidAdresse)
.HasConstraintName("fk_User_Adresse1");
});
modelBuilder.Entity<Adresse>(entity =>
{
entity.HasKey(e => e.IdAdresse)
.HasName("PRIMARY");
entity.HasIndex(e => e.FidPlzOrt)
.HasName("fk_Adresse_plz_ort1_idx");
entity.HasOne(d => d.FidPlzOrtNavigation)
.WithMany(p => p.Adresse)
.HasForeignKey(d => d.FidPlzOrt)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("fk_Adresse_plz_ort1");
});
modelBuilder.Entity<PlzOrt>(entity =>
{
entity.HasKey(e => e.IdPlzOrt)
.HasName("PRIMARY");
});
所以您有一个 id
,并且您想要唯一一个将此 ID 作为主键的用户,以及他的地址和他的 PlzOrt。
Whenever you query, use Select to fetch the data. Only use Include if you want to update the fetched data.
Select 的原因是你有更大的自由select。此外,您可以限制获取的数据:如果您查询学校及其学生,您知道学校 10 的每个学生都有一个等于 10 的外键 SchoolId。那么为什么要为每个学校 1000 个学生获取这个外键?
我不熟悉 ef-core 的可能性。它知道如果您 Select 需要(组)加入的虚拟属性之一吗?在这种情况下,使用 Select.
更容易如果您必须自己进行连接:
var requestedUserWithAddresAndPlz = dbContext.Users.
// keep only the user with id
.Where(user => user.IdUser == id)
// every User has exactly one Address: use a normal join
.Join(dbContext.Addresses,
user => user.IdUser, // from every User take IdUser
address => addres.IdAddress, // from every Address take IdAddress
// result selector: take the user with its address to make one new
(user, address) => new
{
// Select only the User properties you plan to use
Id = user.IdUser,
Name = user.Name,
...
Address = new
{
// again: select only the properties you plan to use
// no need to select IdAddress, you know the value!
Street = address.Street,
HouseNumber = address.HouseNumber,
// to fetch the Plz: fetch the one-and-only PlzOrt with address.FidPlzOrt
Plz = dbContext.PlzOrts
.Where(plzOrt => plzOrt.PlzOrdIt == address.FidPlzOrt)
.FirstOrDefault(),
})
.FirstOrDefault();
注意:我使用匿名类型是为了在 select 只使用我实际计划使用的属性方面有更大的自由度。我也可以给我的属性起我想要的名字。
缺点:不能将匿名类型用作 return 值。如果您确实需要在您的函数之外使用它,请使用创建一个包含您的数据的 class,并使用 new SomeClass()。优点:如果你的数据库发生变化,SomeClass 不必改变,因此你的调用者不会注意到你的数据库中的变化。