如何在LINQ-to-SQL读取SQL Server数据时即刻转换换行符?
我之前也踩过重复写Select转换的坑,完全懂你不想每次都手动处理换行符的心情。给你几个实用的方案,既能遵循DRY原则,又能让你调用m_database.Products或者DataManager里的方法时,自动拿到处理好换行符的Product对象:
方案1:利用部分类扩展实体属性(最推荐)
LINQ-to-SQL生成的Product类是部分类,我们可以在单独的代码文件里扩展它,重写Description属性的getter来自动转换换行符——这样完全不会影响自动生成的代码,重新生成实体类也不会覆盖你的自定义逻辑。
假设LINQ-to-SQL生成的Product类里,私有字段是_Description(你可以打开生成的实体类代码确认字段名),我们这样扩展:
public partial class Product { // 用new关键字覆盖原有的公共Description属性 public new string Description { get { // 统一把\r\n和单独的\r都换成\n return _Description?.Replace("\r\n", "\n").Replace("\r", "\n"); } set { // 可选:如果写入数据库时想统一格式(比如转成SQL Server常用的\r\n),可以在这里处理 _Description = value?.Replace("\n", "\r\n"); } } }
这样一来,不管你是直接调用m_database.Products,还是用DataManager里的GetProduct方法,返回的Product对象的Description都会自动是统一的\n换行符,完全不用再手动写Select转换。
方案2:封装处理后的Products集合
如果你不想修改实体类的属性,可以在DataManager里封装一个预处理好的IQueryable<Product>,把转换逻辑内置进去:
public class DataManager { private readonly MyDataContext m_database; private IQueryable<Product> _processedProducts; // 对外提供处理后的Products集合 public IQueryable<Product> ProcessedProducts { get { if (_processedProducts == null) { _processedProducts = m_database.Products.Select(p => new Product { Id = p.Id, Name = p.Name, Description = p.Description?.Replace("\r\n", "\n").Replace("\r", "\n"), // 注意:要把Product类的所有字段都手动复制一遍 // 这个方案的缺点是字段多的话维护麻烦 }); } return _processedProducts; } } // 修改原有方法,使用处理后的集合 public Product GetProduct(int i_id) { return ProcessedProducts.Where(p => p.Id == i_id).FirstOrDefault(); } public Product GetProductByName(string i_name) { return ProcessedProducts.Where(p => p.Name == i_name).FirstOrDefault(); } }
这个方案的缺点是需要手动复制所有字段,后续表结构变更时要同步修改,所以优先级不如方案1。
方案3:数据库层面自定义函数(进阶)
如果你希望转换逻辑在数据库查询阶段就完成,可以在SQL Server里创建一个标量函数:
CREATE FUNCTION dbo.ConvertNewlines(@input NVARCHAR(MAX)) RETURNS NVARCHAR(MAX) AS BEGIN -- 把\r\n和单独的\r都替换成\n RETURN REPLACE(REPLACE(@input, CHAR(13)+CHAR(10), CHAR(10)), CHAR(13), CHAR(10)); END
然后在LINQ-to-SQL设计器里添加这个函数,之后就可以在查询中直接调用:
var processedProducts = m_database.Products.Select(p => new Product { Id = p.Id, Name = p.Name, Description = m_database.ConvertNewlines(p.Description) // 其他字段 });
不过这个方案需要改动数据库,且大数量查询时可能影响性能,所以只推荐在特定场景下使用。
总的来说,方案1是最简洁、最符合DRY原则的,只需要写一次扩展代码,所有地方的Product对象都会自动处理换行符,完美解决重复代码的问题。
内容的提问来源于stack exchange,提问作者Simone

