如何使用实体框架进行连接表搜索?
Posted
技术标签:
【中文标题】如何使用实体框架进行连接表搜索?【英文标题】:How to make a join table search with Entity Framework? 【发布时间】:2021-08-26 15:08:46 【问题描述】:所以我制作了一个带有搜索文本框的 Windows 表单,该文本框将返回您在数据网格中输入的字符串部分。但是,在我尝试编写以下事件时。数据网格改为显示布尔值。
代码的哪些部分使所有这些结果变为布尔值,我该如何解决这个问题?
private void txtSearch_TextChanged(object sender, EventArgs e)
this.dataGridView1.DataSource = null;
this.dataGridView1.Rows.Clear();
using (var context = new edeappEntities1())
var data = context.bookingorders
.Join(
context.addressbooks,
booking => booking.addrID,
address => address.addrID,
(booking, address) => new
accID = booking.accID.Contains(txtSearch.Text),
bookId = booking.bookingID.Contains(txtSearch.Text),
companyName = address.companyName.Contains(txtSearch.Text),
address = address.addressLn1.Contains(txtSearch.Text) || address.addressLn2.Contains(txtSearch.Text) ||
address.addressLn3.Contains(txtSearch.Text),
region = address.region.Contains(txtSearch.Text),
postcode = address.postcode.Contains(txtSearch.Text),
contact = address.contectName.Contains(txtSearch.Text),
phone = address.phoneNo.Contains(txtSearch.Text),
fax = address.faxNo.Contains(txtSearch.Text),
telex = address.telexNo.Contains(txtSearch.Text),
pickupTime = booking.pickupDate.Contains(txtSearch.Text)
|| booking.pickupTime.Contains(txtSearch.Text)
).ToList();
foreach (var db in data)
dataGridView1.Rows.Add(db.accID, db.bookId, db.companyName, db.address, db.region,
db.postcode, db.contact, db.phone, db.fax, db.telex, db.pickupTime);
我的建模结构:model1.edmx
搜索结果为布尔值:link
【问题讨论】:
你能发布两个实体的类的定义吗? 类的定义是什么意思,我该如何向您展示? 例如accID = booking.accID.Contains(txtSearch.Text)
这将返回一个bool
是否值booking.accID
包含匹配项。你到底想在这里做什么?您是否想要所有数据,但只需要其中一个字段匹配?还是您想要所有数据,但只返回包含匹配项的每一列,否则为空?还是您想要相同但带有文本索引?
@FurukawaHikaru 由于您使用的是实体框架,因此两个数据库表都必须有一个对应的 address
和 booking
类,这正是我所说的。无论如何,我现在已经解决了问题,请参阅我的答案。让我知道是否有帮助:)
【参考方案1】:
您在所有列中都获得了布尔结果,因为您正在创建一个新的匿名类型并将string.Contains()
方法的结果分配给该新匿名类型中的每个属性,并且string.Contains()
返回一个布尔值(bool
) .
例如,如果我这样做:
string str = "Hello!"
bool result = str.Contains("o");
这里,Contains()
方法将返回一个布尔值,指示字符串中是否包含指定的子字符串(“o”)。这里的返回值将是true
,它将被分配给result
。
在您的代码中,您对每个字段执行类似的操作:
accID = booking.accID.Contains(txtSearch.Text)
这将检查booking.accID
是否包含在txtSearch.Text
中捕获的用户搜索的字符串。如果您的booking.accID
包含txtSearch.Text
,则该方法将返回true
和false
(如果它不包含搜索文本)。这将创建一个名为accId
的bool
类型的新变量,返回值将存储在=
左侧的accId
中。
匿名类型
在 C# 中,匿名类型是一种无需实际创建类即可创建包含一组属性的包装对象的快捷方式。
例如,我想要一个包含某人详细信息的对象,而不创建 Person
类,我可以这样做:
var myPerson = new Name = "John", Age = 25, Salary = 10_000L ;
现在,我有一个包含属性Name
、Age
和Salary
的对象,甚至没有创建Person
类。编译器在后台创建一个隐藏类。更多关于匿名类型here。
您正在创建一个 lambda 函数,该函数返回一个匿名类型作为 Join()
方法的第四个参数。这个 lambda 函数将在连接操作的每个结果上调用。
解决方案
过滤条件应该在Where()
方法中指定,而不是分配给匿名类型的属性。应该使用匿名类型来捕获和组合这两个结果:
var searchData = context
.bookingorders
.Join(
context.addressbooks,
booking => booking.addrID,
address => address.addrID,
(booking, address) => new
Booking = booking,
Address = address
)
.Where(data =>
data.Booking.bookingID.Contains(txtSearch.Text) ||
data.Address.companyName.Contains(txtSearch.Text) ||
data.Address.addressLn1.Contains(txtSearch.Text) ||
data.Address.addressLn2.Contains(txtSearch.Text) ||
data.Address.region.Contains(txtSearch.Text) ||
data.Address.postcode.Contains(txtSearch.Text) ||
data.Address.contectName.Contains(txtSearch.Text) ||
data.Address.phoneNo.Contains(txtSearch.Text) ||
data.Address.faxNo.Contains(txtSearch.Text) ||
data.Address.telexNo.Contains(txtSearch.Text) ||
data.Booking.pickupDate.Contains(txtSearch.Text) ||
data.Booking.pickupTime.Contains(txtSearch.Text)
)
.ToList();
foreach(var row in searchData)
dataGridView1.Rows.Add(
row.Booking.bookingId,
row.Address.companyName,
$"row.Address.addressLn1 row.Address.addressLn2",
row.Address.region,
row.Address.postcode,
row.Address.contectName,
row.Address.phoneNo,
row.Address.faxNo,
row.Address.telexNo,
row.Booking.pickupDate,
row.Booking.pickupTime
);
【讨论】:
以上是关于如何使用实体框架进行连接表搜索?的主要内容,如果未能解决你的问题,请参考以下文章
如何在实体框架中的两个表之间进行左连接操作时从左表中选择唯一行