PredicateBuilder, build predicate over 2 tables using EF

点点圈 提交于 2019-12-11 08:24:14

问题


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, Rooms 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!