Как использовать LINQ To SQL в решении N-уровня?
Теперь, когда LINQ to SQL немного более зрелый, я хотел бы узнать о любых методах, которые люди используют для создания n-уровневого решения с использованием технологии, потому что это не кажется мне очевидным.
Ответы
Ответ 1
LINQ to SQL на самом деле не имеет n-уровневой истории, которую я видел, поскольку созданные ею объекты создаются в классе вместе с остальной частью, у вас на самом деле нет сборки, которую вы можете красиво ссылаясь на что-то вроде веб-сервисов и т.д.
Единственный способ, которым я действительно считаю, - использовать datacontext для извлечения данных, затем заполнить промежуточную модель данных, передать ее и ссылаться на нее с обеих сторон и использовать ее на стороне клиента - затем передать их обратно и выталкивание данных обратно в новый Datacontext или intellgently update rows после их восстановления.
Что, если я понимаю, к чему вы пытаетесь добраться:\
Я спросил у ScottGu тот же вопрос в своем блоге, когда я впервые начал смотреть на него, но я не видел ни одного сценария или приложения в дикой природе, которое таким образом использует LINQ to SQL. Веб-сайты, такие как Rob Connery Storefront, ближе к поставщику.
Ответ 2
Hm, Rockford Lhotka, что LINQ to SQL - прекрасная технология для сбора данных из базы данных. Он предполагает, что впоследствии они должны быть привязаны к "достигать доменных объектов" (иначе CSLA objetcs).
Серьезно, LINQ to SQL поддерживал архитектуру n-уровня с помощью метода DataContext.Update.
Ответ 3
Возможно, вы захотите изучить ADO.Net Entity Framework как альтернативу LINQ to SQL, хотя она также поддерживает LINQ, Я полагаю, что LINQ to SQL рассчитан на простоту и простоту, тогда как платформа Entity Framework более сложна и, вероятно, более подходит для крупных корпоративных приложений.
Ответ 4
Хорошо, я дам себе одно возможное решение.
Вставки/обновления никогда не были проблемой; вы можете объединить бизнес-логику в метод Save/Update; например.
public class EmployeesDAL
{
...
SaveEmployee(Employee employee)
{
//data formatting
employee.FirstName = employee.FirstName.Trim();
employee.LastName = employee.LastName.Trim();
//business rules
if(employee.FirstName.Length > 0 && employee.LastName.Length > 0)
{
MyCompanyContext context = new MyCompanyContext();
//insert
if(employee.empid == 0)
context.Employees.InsertOnSubmit(employee);
else
{
//update goes here
}
context.SubmitChanges();
}
else
throw new BusinessRuleException("Employees must have first and last names");
}
}
Для получения данных или, по крайней мере, выборки данных, которые поступают из более чем одной таблицы, вы можете использовать хранимые процедуры или представления, потому что результаты не будут анонимными, поэтому вы можете вернуть их из внешнего метода. Например, используя хранимую процедуру proc:
public ISingleResult<GetEmployeesAndManagersResult> LoadEmployeesAndManagers()
{
MyCompanyContext context = new MyCompanyContext();
var emps = context.GetEmployeesAndManagers();
return emps;
}
Ответ 5
Серьезно, LINQ to SQL поддерживал поддержку архитектуры n-уровня, используя метод DataContext.Update
Некоторые из прочитанных явлений предполагают, что бизнес-логика обертывает DataContext - другими словами, вы переносите обновление так, как вы предлагаете.
Как я обычно пишу бизнес-объекты, я обычно инкапсулирую "методы загрузки" в BO; поэтому у меня может быть метод с именем LoadEmployeesAndManagers, который возвращает список сотрудников и их непосредственных менеджеров (это надуманный пример). Возможно, это только я, но в моем интерфейсе лучше видеть e.LoadEmployeesAndManagers(), чем некоторый длинный оператор LINQ.
В любом случае, используя LINQ, он, вероятно, будет выглядеть примерно так (не проверяется правильность синтаксиса):
var emps = from e in Employees
join m in Employees
on e.ManagerEmpID equals m.EmpID
select new
{ e,
m.FullName
};
Теперь, если я правильно понял вещи, если я помещу это в библиотеку классов и назову его из моего интерфейса, единственный способ, которым я могу это вернуть, - это IEnumerable, поэтому я теряю свою сильную типизированную доброту. Единственный способ вернуть строго типизированный объект - создать собственный класс Employees (плюс поле строки для имени менеджера) и заполнить его из результатов моего оператора LINQ to SQL, а затем вернуть его. Но это похоже на интуитивно понятный... что именно LINQ to SQL купит мне, если я должен все это сделать?
Я думаю, что я мог бы смотреть на вещи не так; любое просвещение будет оценено.
Ответ 6
"единственный способ вернуть это как IEnumerable, поэтому я теряю свою сильную типизированную доброту"
неверно. На самом деле ваш запрос строго типизирован, это просто анонимный тип. Я думаю, что запрос, который вы хотите, больше похож:
var emps = from e in Employees
join m in Employees
on e.ManagerEmpID equals m.EmpID
select new Employee
{ e,
m.FullName
};
Что вернет IEnumerable.
Вот статья, которую я написал по этой теме.
Linq-to-sql - это ORM. Это не влияет на то, как вы разрабатываете N-многоуровневое приложение. Вы используете его так же, как и любой другой ORM.
Ответ 7
@liammclennan
Что вернет IEnumerable.... Linq-to-sql - это ORM. Это не влияет на то, как вы разрабатываете N-многоуровневое приложение. Вы используете его так же, как и любой другой ORM.
Тогда, я думаю, я все еще смущен. Да, Linq-to-Sql является ORM; но, насколько я могу судить, я все еще засоряю свой код переднего конца встроенными операторами типа sql (linq, а не sql.... но все же я считаю, что это должно быть абстрагировано от переднего конца).
Предположим, что я завершаю оператор LINQ, который мы использовали в качестве примера в методе. Насколько я могу судить, единственный способ вернуть его - так:
public class EmployeesDAL
{
public IEnumerable LoadEmployeesAndManagers()
{
MyCompanyContext context = new MyCompanyContext();
var emps = from e in context.Employees
join m in context.Employees
on e.ManagerEmpID equals m.EmpID
select new
{ e,
m.FullName
};
return emps;
}
}
Из моего кода переднего конца я бы сделал что-то вроде этого:
EmployeesDAL dal = new EmployeesDAL;
var emps = dal.LoadEmployeesAndManagers();
Это, конечно, возвращает IEnumerable; но я не могу использовать это, как любой другой ORM, как вы говорите (если, конечно, я не понимаю), потому что я не могу этого сделать (опять же, это надуманный пример):
txtEmployeeName.Text = emps[0].FullName
Это то, что я имел в виду под "Я теряю крепкую типизированную доброту". Я думаю, что я начинаю соглашаться с Crucible; что LINQ-to-SQL не был предназначен для использования таким образом. Опять же, если я не вижу вещи правильно, кто-то покажет мне способ:)