代码之家  ›  专栏  ›  技术社区  ›  David Glenn

将poco映射到linq到sql中的字符串,以便在poco上使用linq

  •  1
  • David Glenn  · 技术社区  · 15 年前

    我正在访问一个数据库列,其中一个电话号码以varchar格式存储,格式为+a-b:c,其中a=国家代码,b=电话号码,c=分机。例如+44-07700123456:123

    所以我有一个类型,它处理沿着以下行的序列化:

    public struct PhoneNumber {
      public PhoneNumber(string val) {  /*...*/ }
      public override string ToString() { /*...*/ }
      public static PhoneNumber TryParse(string val) { /*...*/ }
    }
    

    以及一个POCO:

    public class Customer {
      public PhoneNumber? HomePhone;
    }
    

    然后在我的数据访问代码中,一些LINQ沿着以下行:

    public IQueryable<Customers> GetCustomers() {
      var customers = (from c in DataContext.Customers
      select new Customer {
        HomePhone = PhoneNumber.TryParse(c.HomePhone)
      });
      return customers;
    }
    

    到目前为止,从数据库中检索记录时,这一切都很好,但我的问题是无法对以下结果执行LINQ查询:

    GetCustomers().Where(c => c != null && c.HomePhone.Value.ToString().Contains("123"));
    

    我得到一个错误“method”system。可以为空的“1[phonenumber]typarse(system.string)”不支持转换为sql。现在我知道我可以在getCustomers()中执行电话号码搜索,但这并不理想。

    有没有一种方法可以让Linq知道如何将Linq转换为SQL?所以我可以做一些类似getCustomers()的事情。在哪里(c=>c.homePhone.value.toString().contains(“123”)?

    P.S.不确定这本书的标题,欢迎有其他选择。

    2 回复  |  直到 15 年前
        1
  •  0
  •   dahlbyk    15 年前

    问题是你的 PhoneNumber.TryParse() 调用被转换成一个向上发送到服务器的表达式,但它无法理解。此外,无法将您的结构告诉SQL,因此您将无法基于解析的值执行服务器端查询。一个选项是捕获字符串值并移动 电话号码.typarse() 在别的地方咬。例如:

    public class Customer {
      public string HomePhoneString;
    
      private bool _HomePhoneParsed;
      private PhoneNumber? _HomePhone;
      public PhoneNumber? HomePhone
      {
        get
        {
          if(!_HomePhoneParsed)
          {
            _HomePhone = PhoneNumber.TryParse(HomePhoneString);
            _HomePhoneParsed = true;
          }
          return _HomePhone;
        }
      }
    }
    
    public IQueryable<Customers> GetCustomers() {
      var customers = (from c in DataContext.Customers
      select new Customer {
        HomePhoneString = c.HomePhone
      });
      return customers;
    }
    

    然后您可以查询服务器端:

    GetCustomers().Where(c => c.HomePhoneString != null && c.HomePhoneString.Contains("123"))
    

    或客户端:

    GetCustomers().AsEnumerable()
                  .Where(c => c.HomePhone != null && c.HomePhone.Value.Contains("123"))
    
        2
  •  0
  •   David Glenn    15 年前

    接下来,另一种解决方案是将PhoneNumber更改为类,并添加“Value”属性以进行序列化/反序列化,如下所示:

    public class PhoneNumber {
    
      public override string ToString() { /*...*/ }
      public Parse(string val) { /*...*/ }
    
      public string Value {
        get {
          return ToString();
        }
        set {
          Parse(value);
        }
      }
    }
    

    这种代码实际上不适合属性,但它允许您在LINQ查询中初始化homephone对象,例如:

    var customers = (from c in DataContext.Customers
      select new Customer {
        FirstName = c.FirstName,
        HomePhone = new PhoneNumber {
          Value = c.HomePhone
        }
      });
    

    这意味着您可以使用序列化程序,如:

    customers.Where(x => x.HomePhone.Value.Contains("123"));