问题
I've got a complex problem, but the explanation of it is even more complex (I think). But I'll give it a try anyway, if it's not clear, please ask me to elaborate.
I have a table called UserService
. A service is whatever a user offers, for example a band that plays in a cafe. Another one is DJ and room. Here is what the table looks like:
[Table("UserService")]
public class UserService
{
public int Id { get; set; }
public string UserId { get; set; }
public string Name { get; set; }
public string Information { get; set; }
public Type Type { get; set; }
[ForeignKey("UserId")]
public virtual ApplicationUser User { get; set; }
}
Type
is an enum
for all possible services.
The room is a special case because it requires some additional fields that are not always required/needed, like address and geolocation. For these reasons I created a separate table for it:
public class Room
{
public int Id { get; set; }
public int UserServiceId { get; set; }
public string Street { get; set; }
public string ZipCode { get; set; }
public int HouseNumber { get; set; }
public string City { get; set; }
public DbGeography GeoLocation { get; set; }
[ForeignKey("UserServiceId")]
public virtual UserService UserService { get; set; }
}
When filtering on a user service (all combo's are possible), which I construct with a PredicateBuilder.
Suppose the user selects Band and Room but when room is selected, the user should also pass a city or zip code (or anything else to get a geolocation from) and a distance in miles to look for a room. How can I build the predicate over 2 tables?
If I do this:
var userServices = PredicateBuilder.Create<UserService>(x => lstTypes.Contains(x.Type));
Than I can't do anything with the GeoLocation
field in the Room table, because UserService
doesn't have it. So this won't work:
userServices = userServices.And(x => x.GeoLocation.Distance(geo) < distance);
Also, I need these userservices combined because of the Orderby().Skip().Take()
I use. So this will get messed up if I separate them and going twice to the database because of this.
I was thinking about adding a navigation property Room
to UserService
but I'm not sure what this might do in the short and long term. Since it's not always required.
回答1:
The way you have things now, Room
s effectively have a many-to-one relationship with UserService
because they have a foreign key to that table.
You could leave this as-is, and add a Rooms
property to UserService
, in which case you'd have to see whether x => x.Rooms.Any(r => r.GeoLocation.Distance(geo) < distance)
. If there is no room associated with the service, then the .Any()
would obviously return false.
However, you're making it sound like a Room is simply an optional property off of UserService
, in which case you may want to make UserServiceId
its primary key as well as its foreign key. Then your predicate would be x => x.Room.GeoLocation.Distance(geo) < distance
. The weird thing is that while C# would throw an exception from this code, the generated SQL ends up propagating null values so it should come out effectively false
if x.Room
turns out to be null.
来源:https://stackoverflow.com/questions/22211471/predicatebuilder-build-predicate-over-2-tables-using-ef