按字符串名称获取列

时间:2018-01-10 05:38:49

标签: linq

我正在尝试更新给定客户ID,行ID和动态列名称的记录。

到目前为止,我有以下内容,故障点标记为***:

    public void UpdateRecord(int Id, string rval, string column, string value)
    {
        var rId = GetRvalId(rval);
        var entry = _context.Customers
            .Where(x => x.Id == Id && x.RVals.Id == rId && x.***column?*** == column).First();
        entry = value;
    }

我无法找到如何做到这一点的好例子。

2 个答案:

答案 0 :(得分:2)

最后评论后添加

您无法找到示例的原因是因为它不是一个好的设计。

您的方法非常容易出错,难以测试且难以维护。如果有人输入错误的列名怎么办?如果您尝试将字符串分配给客户的生日怎么办?即使您要对列名和建议值执行一些字符串检查,在有人更改列的名称或类型后,您的程序也不再有效。

让我们重新设计!

显然,您有一个Customer Id和一个属性Rvals。此属性Rvals也有一个属性Id

您还有一个函数GetRValId,可以将字符串rval转换为int rvalId

您想要的是Id和字符串rval,您希望使用此IdrValId更新第一个客户的其中一列。

附带问题:ID可以有多个客户吗?在这种情况下:你确定Id是一个ID吗?如果有更多匹配的客户,您想要什么?更新所有客户或仅更新第一个客户?您将哪个客户定义为第一个客户?

抛开旁边的问题。我们想要一个函数签名,如果您使用不存在的客户属性,或者如果您尝试将字符串分配给生日,则在编译时报告错误。这样的事可能呢?

更新客户名称:

int customerId = ...
string rval = ...
string proposedName = "John Doe";
UpdateCustomerRecord(id, rval, customer => customer.Name = proposedName);

更新客户的生日:

DateTime proposedBirthday = ...
UpdateCustomerRecord(id, rval, customer => customer.Birthday = proposedBirthday)

这样就不能使用任何不存在的列,也不能将字符串赋给DateTime。

您想在一次通话中更改两个值吗?来吧:

UpdateCustomerRecord(id, rval, customer =>
{
    customer.Name = ...;
    customer.Birthday = ...;
});

<强>深信?我们来写一下这个函数:

public void UpdateCustomerRecord(int customerId, string rval, Action<Customer> action)
{
    // the beginning is as in your function:
    var rId = GetRvalId(rval);

    // get the customer that you want to update:
    using (var _Context = ...)
    {
        // get the customer you want to update:
        var customerToUpdate = _Context.Customers
            .Where(customer => customer.Id == Id
                && customer.RVals.Id == rId)
            .FirstOrDefault();

        // TODO: exception if there is no customerToUpdate

        // perform the action and save the changes
        action(customerToUpdate);
        _context.SaveChanges();
}

简单的纪念活动!

评论后添加

那么这个功能是做什么的?只要你不打电话,它什么都不做。但是,当您调用它时,它会提取客户,对您在调用中提供的客户执行操作,最后调用SaveChanges。

它不会对每个客户执行此操作,不会仅与ID等于提供的ID和customer.RVals.Id == ...的客户执行此操作(您是否仍然确定有多个客户)有这个Id?如果只有一个,为什么要检查RVals.Id?)

因此调用者不仅必须提供定义要更新的客户的Id和RVal,而且他还必须定义必须对此客户执行的操作。

该定义采用以下形式:

customer =>
{
    customer.Name = X;
    customer.BirthDay = Y;
}

如果您愿意,可以使用除客户之外的其他标识符,但它的含义相同:

x => {x.Name = X; x.BirthDay = Y;}

因为你在调用UpdateCustomerRecord时将它放在 Action 参数的位置,所以我知道x是Customer类型。

Acton声明意味着:如果客户必须更新,我们必须对客户做些什么?你可以把它看作是一个函数:

void Action(Customer customer)
{
    customer.Name = ...
    customer.BirthDay = ...
}

最后它会做类似的事情:

Customer customerToUpdate = ...
customerToUpdate.Name = X;
customerToUpdate.BirthDay = Y;
SaveChanges();

因此,在第三个参数中,名为 Action ,您可以键入任何您想要的内容,甚至调用与客户无关的函数(可能不明智)。您有一个输入参数,您可以确定它是一个客户。

请参阅我之前调用UpdateCustomerRecord的示例,最后一个示例:

UpdateCustomerRecord( GetCustomerId(), GetCustomerRVal,
   // 3rd parameter: the actions to perform once we got the customerToUpdate:
   customer =>
   {
       DateTime minDate = GetEarliestBirthDay();
       if (customer.BirthDay < minDate)
       {   // this Customer is old
           customer.DoThingsThatOldPeopleDo();
       }
       else
       {   // this Customer is young
           customer.DoThingsThatYoungPeopleDo();
       }
   }
}

因此,Action参数只是一种更简单的说法:“一旦您拥有必须更新的客户,请与客户一起执行此功能

因此,如果您只想更新客户的给定属性,请写下以下内容:

UpdateCustomerRecord(... , customer =>
{
     Customer.PropertyThatMustBeUpdated = NewValueOfProperty;
}

当然,这只有在您知道必须更新哪个属性时才有效。但是既然你写了“我正在尝试更新特定的单元格”。我假设您知道此列中的单元格代表哪个属性。

答案 1 :(得分:0)

无法将列名称作为LINQ中的字符串值传递。替代方法,如果你有可以传递的有限数量的列名,那么它可以实现如下:

public void UpdateRecord(int Id, string rval, string column, string value)
{
    var rId = GetRvalId(rval);
    var entry = _context.Customers
        .Where(x => x.Id == Id && 
               x.RVals.Id == rId && 
              (x.column1 == value || column == column1) &&
              (x.column2 == value || column == column2) && 
              (x.column3 == value || column == column3) &&
              (x.column4 == value || column == column4) &&
              (x.column5 == value || column == column5) &&
               )).First();
    entry = value;
}

UpdateRecord(5, "rval", "column1", "value");
UpdateRecord(5, "rval", "column2", "value");
UpdateRecord(5, "rval", "column3", "value");

在这里,假设您在调用函数UpdateRecord时可以传递5列,那么您可以在WHERE中添加5个子句,如上所述。

其他方式动态LINQ

var entry = db.Customers.Where(column + " = " + value).Select(...);