如何在数据层编写Linq方法?
我正在考虑如何在.net项目的经典三层架构中使用Linq。显然,Linq to SQL 应该出现在数据层中。我选择 Linq 的原因是因为它比使用存储过程节省更多的代码时间。我在线搜索了有关 Linq 的插入/更新/删除方法,但没有找到使用实体进行记录更新的合适方法。通常,人们会使用这种方式进行更新:
public void UpdateUser(String username, String password, int userId)
{
using (var db = new UserDataContext()){
var user = db.user.Single(p => p.Id = userId);
user.Username = username;
user.Password = password;
db.SubmitChanges();
}
}
为什么我们不使用实体来像这样传递记录:
public void Update(Application info)
{
VettingDataContext dc = new VettingDataContext(_connString);
var query = (from a in dc.Applications
where a.Id==info.Id
select a).First();
query = info;
try{
dc.SubmitChanges();
}
catch(Exception e){
//...
}
}
但不幸的是,上面的代码是错误的,因为“query=info”,但是如果我从“info”分配每个值到“查询”,它工作正常。如果
query.firstName=info.firstName;
query.lastName=info.lastName;
这个表有 40 个字段,我必须编写 40 行代码。有没有更简单的方法来进行更新?希望我能清楚地描述这个问题。
I am thinking about how to use Linq in the classic 3-tier archetecture of .net project. Apprently, Linq to SQL should appear in Data tier. The reason I choose Linq is because it will save me much time on code than using store procedure. I did some search on line about the insert/update/delete method of Linq, but didn't find an appropriate method for record update using entities. Usually, people will do update using this way:
public void UpdateUser(String username, String password, int userId)
{
using (var db = new UserDataContext()){
var user = db.user.Single(p => p.Id = userId);
user.Username = username;
user.Password = password;
db.SubmitChanges();
}
}
Why we don't use entity to pass the record like this:
public void Update(Application info)
{
VettingDataContext dc = new VettingDataContext(_connString);
var query = (from a in dc.Applications
where a.Id==info.Id
select a).First();
query = info;
try{
dc.SubmitChanges();
}
catch(Exception e){
//...
}
}
But unfortunately, the above code is wrong because of "query=info", but if I assign each value from "info" to "query", it works fine. like
query.firstName=info.firstName;
query.lastName=info.lastName;
So if this table have 40 fields, I have to write 40 lines code. Is there any easier way to do the update? Hope I describe this issue clearly.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
添加另一个答案作为评论不足以扩展我之前的答案。
让我们退后一步,从逻辑角度看看您想要在这里做什么。您想告诉数据访问层如何更新数据库,以及需要写入的所有新的/更改的值。
执行此操作的一种非常常见的方法是传递具有这些更改的实体(这就是您在示例中所做的)。正如您所看到的,这可能会变得很棘手,因为如果您只是用更改的实体覆盖实体变量,Linq2Sql 将失去更改跟踪...仅仅因为新实体被分配给相同的变量,并不意味着 Linq2Sql 自动从新对象中获取更改...事实上 Linq2Sql 根本不知道新对象...
示例:
现在您已经看到将每个字段分配给实体而不是按预期替换它 - 这是因为更改是对原始实体进行的,而原始实体仍在 Linq2Sql 更改跟踪系统内。
此问题的一种可能的解决方案是编写一种方法,将另一个实体的更改“应用”到现有实体,即:
然后您的数据访问将如下所示:
但我确定您不喜欢这个解决方案 - 因为您所做的只是有效地将重复的字段分配从存储库移出并移入实体类本身...
回到逻辑角度 - 您真正需要做的就是告诉数据访问存储库 2 件事 - 1) 您想要更新哪些记录,2) 更改是什么。发送一个封装这两个要求的全新实体对于实现该目标来说并不是必要的,事实上我认为这是非常低效的。
在以下示例中,您仅向数据存储库发送更改,而不是整个实体。由于没有实体,因此没有需要解决的更改跟踪问题
示例:
在前面的示例中,字段分配发生了两次 - 一次是在您描述想要进行的更改时,另一次是在数据存储库中当您需要时将这些更改应用到 Linq2Sql 更改跟踪实体。
使用回调,字段分配仅发生一次 - 更改本身的描述就是更新跟踪实体的内容。
我希望我解释得足够好:)
Adding another answer as a comment was not sufficient to expand on my previous answer.
Lets take a step back and look at what you want to do here from a logical perspective. You want to tell your data access layer how it should update the database, with all the new/changed values it needs to write.
One very common way of doing this is to pass an entity which has those changes (which is what you're doing in your example). This can become tricky, as you have seen, because if you simply overwrite the entity variable with the changed entity, Linq2Sql will lose change tracking... just because the new entity is assigned to the same variable, doesn't mean that Linq2Sql automatically picks up changes from the new object... in fact Linq2Sql has no knowledge of the new object at all...
Example:
Now you've already seen that assigning each field to the entity rather than replacing it works as intended - this is because the changes are being made to the original entity, which is still inside the Linq2Sql change tracking system..
One possible solution to this problem would be to write a method that "applies" the changes of another Entity to an existing one, ie:
and then your data access would look like this:
But im sure you don't like this solution - because all you have done is effectively move the repetitive field assignment out of the repository and into the Entity class itself...
Going back to the logical perspective - all you really need to do is tell the data access repository 2 things - 1) which record you want to update and 2) what the changes are. Sending an entirely new entity which encapsulates those two requirements is not necessary to achieve that goal, in fact I think it's very inefficient.
In the following example, you are sending the data repository only the changes, not an entire entity. Becuase there is no entity, there are no change tracking issues to work around
Example:
In the previous examples, the field assignments were happening twice - once when you described the changes you wanted to make, and again in the data repository when you needed to apply those changes to a Linq2Sql change tracked entity.
Using the callback, the field assignments only happen once - the description of the change itself is what updates the tracked entity.
I hope I explained this well enough :)
考虑一下数据存储库实际需要什么才能执行更新。它不需要包含这些更改的对象,而是需要进行哪些更改的描述。这可以很容易地封装到回调委托中......
Think about what the data repository actually requires in order to perform the update. It does not require an object that contains those changes, but a description of what changes need to be made. This can be encapsulated easily into a callback delegate...
query
与info
的类型不同。它们可能具有与您相同的属性,但代码不知道这一点。现在,如果您想避免编写一堆不必要的代码,您可以使用第三方库,例如 AutoMapper可以为你做到这一点。
query
is not the same type asinfo
. They may have the same properties to you, but the code doesn't know that.Now, if you want to avoid writing a bunch of unnecesary code, you can use a third party library like AutoMapper which can do that for you.