简体   繁体   English

如何使用linq在C#中有效过滤包含特定属性的列表

[英]How to efficiently filter a list in c# with linq that contains certain attributes

I am busy implementing an api controller that returns a list of devices, 我正在忙于实现一个api控制器,该api控制器返回设备列表,

Here is my current helper method: 这是我当前的帮助方法:

private List<Device> GetUsersDevices(string userName)
    {
        int userId = -1;
        List<Device> myDevices;
        if (Int32.TryParse(User.Identity.Name, out userId))
        {
            myDevices = db.Devices.Where((x => x.EndUserId == userId && x.Deleted == false)).OrderByDescending(x => x.LastComms).ToList();
            return myDevices;
        }
        return null;
    }

Now this is all good, But I now need to add a rule that it only returns certain devices (one compatible to the end client) 现在一切都很好,但是我现在需要添加一条规则,使其仅返回某些设备(一个与最终客户端兼容的设备)

So I want to make a list of the allowed device types for a end client like the psuedo code below: 因此,我想列出最终客户端允许的设备类型,例如下面的psuedo代码:

List endclient1 = device type 1, device type 2 etc. List endclient2 = device type 2, device type 5 etc. List endclient1 = device type 1, device type 2 etc. List endclient2 = device type 2, device type 5 etc.

But then I want to filter my list of devices to remove all the unsupported devices. 但是,然后我想过滤我的设备列表以删除所有不支持的设备。 Now I understand that I can just continue adding to the .Where(...) clause in my original statement, but I want to know the most efficient way to go about doing this, And also If the amount of device types grows large it will not be very easy to maintain that line of code. 现在,我了解到我可以继续在原始语句中继续添加.Where(...)子句,但是我想知道执行此操作的最有效方法,而且如果设备类型的数量增加,维护那行代码并不是一件容易的事。 And I would possibly like to have different list of supported devices for different end clients, So if I could filter by a list of allowed devices it will allow me to have one controller serving all the different end clients, and it will just return what device they are allowed. 而且我可能希望针对不同的最终客户端具有不同的受支持设备列表,因此,如果我可以按允许的设备列表进行过滤,则可以让我有一个控制器为所有不同的最终客户端提供服务,并且它将仅返回哪个设备他们被允许。

Other Info that might be needed. 可能需要其他信息。

Here is the MyDevice Class 这是MyDevice类

    public class MyDevice
{        
    public MyDevice(long deviceId, string name, string serialNo, string deviceType, int deviceTypeId, bool enabled)
    {
        this.deviceId = deviceId;
        this.name = name;
        this.serialNo = serialNo;
        this.deviceTypeName = deviceType;
        this.deviceTypeId = deviceTypeId;
        this.enabled = enabled;
    }

    public string name { get; set; }
    public long deviceId { get; set; }
    public string serialNo { get; set; }
    public string deviceTypeName { get; set; }
    public int deviceTypeId { get; set; }
    public bool enabled { get; set; }
}

If I understand your question correctly, you want to do something like this: 如果我正确理解了您的问题,则您想要执行以下操作:

var allowedDeviceTypes = GetAllowedDeviceTypesForUser(userId);

return db.Devices
  .Where(x => x.EndUserId == userId && x.Deleted == false)
  .Where(x => allowedDeviceTypes.Contains(x.deviceTypeId))
  .OrderByDescending(x => x.LastComms)
  .ToList();

This will be translated to a WHERE deviceTypeId IN (...) clause (assuming you're using LINQ to SQL, Entity Framework or NHibernate), which is efficient enough for a reasonable number of device types. 这将转换为WHERE deviceTypeId IN (...)子句(假设您使用的是LINQ to SQL,Entity Framework或NHibernate),对于足够数量的设备类型而言,它足够有效。

Note that the method GetAllowedDeviceTypesForUser has nothing to do with LINQ, and you're free to implement it however you want (eg delegate it to another service, add custom rules etc.). 请注意,方法GetAllowedDeviceTypesForUser与LINQ无关,您可以随意实现它(例如,将其委派给其他服务,添加自定义规则等)。 As long as you have a way of getting a list of allowed device types, you can pass that to the LINQ query. 只要您有一种获取允许的设备类型列表的方法,就可以将其传递给LINQ查询。

Here's a trivial implementation: 这是一个简单的实现:

private IDictionary<int, IList<int>> _allowedDeviceTypesPerUserId = 
  new Dictionary<int, IList<int>>() {
    { 1, new[] { 1, 2 } },
    { 2, new[] { 2, 5 } },
    // ...
  };

private IList<int> GetAllowedDeviceTypesForUser(int uesrId)
{
    return _allowedDeviceTypesPerUserId[userId];
}

This is assuming the list of allowed devices per user is static. 这是假设每个用户允许的设备列表是静态的。 If it's dynamic, you'll have to load it from somewhere, in which case you might also consider using a Join but I'm not sure that's the best idea in your case. 如果它是动态的,则必须从某个位置加载它,在这种情况下,您可能还考虑使用Join但是我不确定这是您的最佳选择。

You can take a look at join to give you an intersection of the "all devices" list and the "compatible devices" list, based on a key, in this case deviceId . 您可以看一下join ,它基于一个键(在本例中为deviceId为您提供了“所有设备”列表和“兼容设备”列表的deviceId

In this case, you would do something like (not checked for syntax correctness): 在这种情况下,您可以执行以下操作(不检查语法正确性):

db.Devices.Join(endClientList, d => d.deviceId, ecd => ecd.deviceId, d => d);

This is just from the top of my head, so there may be some errors in there, but you should be able to figure out how to use it if you want. 这只是从我的头上来的,所以那里可能有一些错误,但是如果您愿意,您应该能够弄清楚如何使用它。

Unless you have a few billion Devices I think you find plain old LINQ more than efficient: 除非您拥有数十亿个设备,否则我认为您会发现普通的老式LINQ比效率更高:

myDevices = from device in db.Devices
            where device.EndUserId == userId 
              && device.Deleted == false
              && allowedTypes.Contains(device.Type)
            order by device.LastComms
            select device;

It is the most readable and maintainable too! 它也是最易读和可维护的!

Another advantage of this is standard LINQ is compilers jitters conversions to SQL can all optimise this standard stuff - have you measured it's speed - is it a problem and have you compared it to alternatives? 此标准的另一个优点是标准LINQ,即编译器将抖动转换为SQL都可以优化此标准标准-您是否测量了速度-是否有问题,是否已将其与替代方法进行了比较?

I'm not sure I understand your question.But I will do just like this: 我不确定我是否理解您的问题。但是我会这样做:

    int userId = -1;
    List<Device> myDevices;
    if (Int32.TryParse(User.Identity.Name, out userId))
    {
        myDevices = db.Devices.Where((x => x.EndUserId == userId && x.Deleted == false)).OrderByDescending(x => x.LastComms).ToList();
        var result1 = myDevices.Where(x=>x.name==someName);
        var result2 = myDevices.Where(x=>x.deviceId >someDeviceId );
        var result3 = myDevices.Where(x=>x.serialNo.Contains("someSerialNo"));
        ....
        return resultN.ToList();
    }

or 要么

myDevices = from item in db.Devices
            where item.name == someName && item.deviceId == someDeviceId && ...
            where ...
            OrderByDescending item.LastComms
            select item;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM