我正在尝试现有数据库的模型优先方法。我无法以任何方式改变数据库方案。
此数据库有一组有趣的关系:用户与地址有一对多的关系。但是,地址有一个'IsActive'字段,对于任何给定的用户,只有一个地址是活动的。
我正在寻找一种方法,以便让实体框架理解这一点,以便开发人员在他们的模型中建立关系,好像它是一对一/一关系:user.Addresses.SingleOrDefault(c => c.IsActive).Line1
。
我需要一个真正的导航属性。我不只是试图避免每次都重复usaCust = customers.Where(c => c.Address.Country == "USA");
。实际导航属性允许更复杂的场景,例如从数据库延迟加载或急切加载,或过滤:#Server
import threading
import socket
import math
import random
import ssl
def within(guess,goal,n):
absValue = abs(guess - goal)
if absValue <= n:
return True
else:
return False
#def HandleAdmin(adminSocket):
#(conn,addr) = adminSocket.accept()
#ts = ssl.wrap_socket(conn, certfile="5cc515_server.crt",
#keyfile="5cc515_server.key",
#server_side=True,
#cert_reqs=ssl.CERT_REQUIRED,
#ca_certs="5cc515-root-ca.cer")
#if ts.recv(80).decode() == 'Hello\r\n':
#ts.send('Admin-Greetings\r\n'.encode())
#if ts.recv(80).decode() == 'Who\r\n':
#ts.send((c,a).encode())
#ts.close()
#return
def HandleClient(c,a):
scoreCount = 0
guess = 0
if(c.recv(80).decode()) == 'Hello\r\n':
c.send('Greetings\r\n'.encode())
goal = random.randrange(1,21)
while guess!= goal:
guess =c.recv(80).decode()
guess = int(guess[7:len(guess)-2])
if guess == goal:
c.send('Correct\r\n'.encode())
elif within(guess, goal, 2) == True:
c.send('Close\r\n'.encode())
else:
c.send('Far\r\n'.encode())
c.close()
return
clientSocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
clientSocket.bind(("127.0.0.1",4000))
clientSocket.listen(5)
adminSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
adminSocket.bind(("127.0.0.1",4001))
adminSocket.listen(5)
while True:
(c,a) = clientSocket.accept()
#handleAdminThread = threading.Thread(target = AcceptAdminConnection,
# args = adminSocket)
clientThread = threading.Thread(target = HandleClient, args = (c,a))
clientThread.start()
。
答案 0 :(得分:1)
您可以简单地将ActiveAddress属性添加到您的实体,并使用它来获取/设置适当的地址为活动状态。
这将有效地为每个用户提供零个或一个ActiveAddresses,可以将其设置为Addresses集合的成员,或设置为null。一次只能激活一个地址。
public class User
{
[Key]
public int ID { get; set; }
public virtual List<Address> Addresses { get; set; }
[NotMapped]
public Address ActiveAddress
{
get { return Addresses == null ? null : Addresses.Where(t => t.IsActive).FirstOrDefault(); }
set
{
if (Addresses != null)
{
//set all addresses inactive
Addresses.ForEach(t => t.IsActive = false);
//set specified address as active if not null
if(value != null)
value.IsActive = true;
}
}
}
}
public class Address
{
[Key]
public int ID { get; set; }
public string FullAddress { get; set; }
public bool IsActive { get; set; }
public int UserID { get; set; }
[ForeignKey("UserID")]
public virtual User User { get; set; }
}
要查询此内容,您需要在引用ActiveAddress字段之前枚举并使用Linq to Objects,因为它在db中不存在。如果您的客户和/或地址表中有大量记录,则这可能不可行。
var usaCustomer = c.Customers.ToList().Where(t => t.ActiveAddress.Country == "USA").FirstOrDefault();
要使用Linq to Entities,我目前唯一能想到的方法是通过地址dbset查询你的集合,地址dbset是你想做的事情的倒退,但仍会在db端执行。
var usaCustomer = c.Customers.Where(t => t.Addresses.Any(a => a.IsActive && a.Country == "USA")).FirstOrDefault();
答案 1 :(得分:0)
您打算对地址进行语义验证。您可以为给定查询实现一个期望into
和var resultsA = a.GroupJoin(b, master => master.Foo, detail => detail.Foo, (master, details) => new
{
master.Foo,
master.Baz,
master.Name,
Code = details.Select(detail => detail.Code).First(),
Bars = details.Select(detail => new { detail.Value, detail.Code })
});
var resultsB =
from master in a
join detail in b on master.Foo equals detail.Foo into details
select new
{
master.Foo,
master.Baz,
master.Name,
Code = details.Select(detail => detail.Code).First(),
Bars = details.Select(detail => new { detail.Value, detail.Code })
};
DateTime
结果的方法,如下所示:
return
您将能够使用它,如下所示:
SingleOrDefault
注意,如果您打算测试其他日期,该方法也支持其他日期。
答案 2 :(得分:0)
一月, 尝试使用动态全局过滤器实体框架
答案 3 :(得分:0)
感谢所有讨论和提议的解决方案。他们真的很有帮助,可能对90%有类似问题的人有用。
如果您可以更改数据库而不需要传入参数,E-Bat建议使用适当的关系制作正确的可更新视图,并使用它们。
如果您不需要预先加载,请创建[NonMapped]计算属性或辅助方法。
我们最终得到了一个不同的解决方案,我不能发布我们最终解决方案的所有技术细节,因为它长约1k代码行...
无论如何,我们真的想以一种方式将1-many关系建模为1-1(在给定时间内),以便我们可以急切地加载关系,延迟加载它,或者在数据库查询中使用它(过滤CurrentAddress等)。
首先,我们在Address类型的User上创建了一个属性,并添加了&#39; NotMapped&#39;属性:
public class User{
public string Name { get; set; } //simple property
public virtual ICollection<Address> Addresses { get; set;} //normal navigation collection
[NotMapped] public virtual Address CurrentAddress { get; set;} //We added this
}
然后,我们看看你通常如何填写这个地址属性:
var users = from user in dbo.Users
join address in dbo.Addresses.Where(a => a.IsActive)
on user.Id equals address.UserId
select new User{
Name = user.Name
Addresses = user.Addresses
CurrentAddress = address
};
我们制作了一个流畅的API,因此我们可以使用类似于您如何使用EF流利API来定义与模型构建器的正常关系的方式来定义此连接。
this.Entity<User>()
.HasJITRelationship(u => u.CurrentAddress)
.From(dbo => dbo.Addresses
.Where(a => a.IsActive)
.On(u => u.Id)
.Equals(a => a.UserId);
最后,假设我们有:
var usaUsers = dbo.Users.Where(c => c.CurrentAddress.Country == "USA");
foreach(var user in usaUsers.ToList()) { //...
只有在调用ToList()时才会执行此IQueryable。此时,usaUsers IQueryable的表达式树包含需要CurrentAddress连接的信息。
我们实际上使我们的DBContext更聪明一些。而不是dbo.Users返回正常的DBSet(),我们实际上返回一个注入逻辑的DBSet。基于这个特定用法(美国用户示例),我们调查表达式树并换出(在运行时)dbo.Users的正常使用,为我们注入&#39; join&#39;的新IQueryable使用一个ExpressionVisitor。
基本上,由于我们使用流畅的API定义了连接一次,并且我们知道了用法(IQueryable.Expression调查),我们可以注入连接&即时&#39;在个案基础上。
我遗漏了大约900条其他技术细节......