linq to sql query interceptor - linq-to-sql

I'm looking at implementing some LINQ to SQL but am struggling to see how we woudl add in access control business rules such as customer a can only view their orders.
In ado.net data services, query intercptors do exactly what I am after, and can see how to check on update / insert / delete, but is there an equivalent of this:
[QueryInterceptor("Orders")]
public IQueryable<Orders> OnQueryOrders(IQueryable<Orders> orderQuery)
{
return from o in orderQuery
where o.Customers.ContactName == HttpContext.Current.User.Identity.Name
select o;
}
Or wil I need to control via accessors along the line of:
GetOrdersByCustomer(string customerId)

I think, in this case, the better solution would be to build a true Business Layer that sits between the Application Layer and your LINQ to SQL classes.
You would then query your Business Layer, which in turn would implement all your Business Logic and filtering. If architected properly, that Business Layer could be fairly transparent to anybody coding the Application Layer and then everybody would be happy.

Related

Generating a DataContext for use with LinqToSql

Similar to how linqpad works, when you just add a database connection, and you automatically get a context to work with.
I did literally like 0 work to get this context.
How do I do something similar in my code?
Say for one of my projects I just want to load up a database
var dataContext = new DataContext(myConnection);
//linqpad has like a typed context, which i'd like
var customer = dataContext.Customers.Where(x => x.Id == 4);
without having to have the Customer class already created and mapped.
How does linqpad do this?
I'm guessing it's some sort of derived data context, but how does it handle the creating of all the models with the correct properties and what not?
Any pointers would be fabulous
LINQPad "cheats" and builds a typed data context behind the scenes using Reflection.Emit. It makes it appear as though something dynamic is going on, but really, it's not that different to adding a "LINQ to SQL Classes" item in like Visual Studio (or using SqlMetal as Stephen suggests).

Linq-to-SQL EntitySet Is Not IQueryable -- Any Workarounds?

When you query an EntitySet property on a model object in Linq-to-SQL, it returns all rows from the entityset and does any further querying client-side.
This is confirmed in a few places online and I've observed the behavior myself. The EntitySet does not implement IQueryable.
What I've had to do is convert code like:
var myChild = ... ;
// Where clause performed client-side.
var query = myChild.Parents().Where(...) ;
to:
var myChild = ... ;
// Where clause performed in DB and only minimal set of rows returned.
var query = MyDataContext.Parents().Where(p => p.Child() == myChild) ;
Does anyone know a better solution?
A secondary question: is this fixed in the Entity Framework?
An EntitySet is just a collection of entities. It implements IEnumerable, not IQueryable. The Active Record pattern specifies that entities be directly responsible for their own persistence. OR mapper entities don't have any direct knowledge of the persistence layer. OR Mappers place this responsibility, along with Unit Of Work, and Identity Map responsibilities into the Data Context. So if you need to query the data source, you gotta use the context (or a Table object). To change this would bend the patterns in use.
I had a similar problem: How can I make this SelectMany use a join. After messing with LINQPad for a good amount of time I found a decent workaround. The key is to push the EntitySet you are looking at inside a SelectMany, Select, Where, etc. Once it's inside that it becomes an Expression and then the provider can turn it into a proper query.
Using your example try this:
var query = from c in Children
where c == myChild
from p in c.Parents
where p.Age > 35
select p;
I'm not able to 100% verify this query as I don't know the rest of your model. But the first two lines of the query cause the rest of it to become an Expression that the provider turns into a join. This does work with my own example that is on the question linked to above.

LINQ-to-SQL performance question

I am getting an IQueryable from my database and then I am getting another IQueryable from that first one -that is, I am filtering the first one.
My question is -does this affect performance? How many times will the code call the database? Thank you.
Code:
DataContext _dc = new DataContext();
IQueryable offers =
(from o in _dc.Offers
select o);
IQueryable filtered =
(from o in offers
select new { ... } );
return View(filtered);
The code you have given will never call the database since you're never using the results of the query in any code.
IQueryable collections aren't filled until you iterate through them...and you're not iterating through anything in that code sample (ah, the beauty of lazy initialization).
That also means that each of those statements will be executed as its own query against the database which results in no performance cost over doing two completely independent queries.
SO is not a replacement for developer tools. There are many good free tools able to tell you exactly what this code translates into and how it works. Use Reflector on this method and look at what code is generated and reason for yourself what is going on from there.

Linq#sql Is it possible to excute sql query with Linq2Sql for a type not defined in codegen

I have an app and I have come to a point where I need to build a
sql statement up dynamically.
Is there a way to execute it and return a type that has not been defined
via the designer with Linq2Sql??
Malcolm
Do you mean an existing Type you yourself defined? That is not possible, you always have to map LINQ2SQL objects to your own object logic (schema objects).
In .NET4 you will have more options for controlling the output type, but only with LINQ2Entities. LINQ2SQL will remain as it is now.
Nope.
You can dynamically create a SQL Query and execute it but it MUST map to a type in the datacontext.
I usually end up creating a view and adding it to the datacontext or using the good old SQLClient library.
c'est la vie

How to use LINQ To SQL in an N-Tier Solution?

Now that LINQ to SQL is a little more mature, I'd like to know of any techniques people are using to create an n-tiered solution using the technology, because it does not seem that obvious to me.
LINQ to SQL doesn't really have a n-tier story that I've seen, since the objects that it creates are created in the class with the rest of it, you don't really have an assembly that you can nicely reference through something like Web Services, etc.
The only way I'd really consider it is using the datacontext to fetch data, then fill an intermediary data model, passing that through, and referencing it on both sides, and using that in your client side - then passing them back and pushing the data back into a new Datacontext or intellgently updating rows after you refetch them.
That's if I'm understanding what you're trying to get at :\
I asked ScottGu the same question on his blog when I first started looking at it - but I haven't seen a single scenario or app in the wild that uses LINQ to SQL in this way. Websites like Rob Connery's Storefront are closer to the provider.
Hm, Rockford Lhotka sad, that LINQ to SQL is wonderful technology for fetching data from database. He suggests that afterwards they'll must to be bind to "reach domain objects" (aka. CSLA objetcs).
Seriously speaking, LINQ to SQL had it's support for n-tier architecture see DataContext.Update method.
You might want to look into the ADO .Net Entity Framework as an alternative to LINQ to SQL, although it does support LINQ as well. I believe LINQ to SQL is designed to be fairly lightweight and simple, whereas the Entity Framework is more heavy duty and probably more suitable in large Enterprise applications.
OK, I am going to give myself one possible solution.
Inserts/Updates were never an issue; you can wrap the business logic in a Save/Update method; e.g.
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");
}
}
For fetching data, or at least the fetching of data that is coming from more than one table you can use stored procedures or views because the results will not be anonymous so you can return them from an outside method. For instance, using a stored proc:
public ISingleResult<GetEmployeesAndManagersResult> LoadEmployeesAndManagers()
{
MyCompanyContext context = new MyCompanyContext();
var emps = context.GetEmployeesAndManagers();
return emps;
}
Seriously speaking, LINQ to SQL had it's support for n-tier architecture see DataContext.Update method
Some of what I've read suggests that the business logic wraps the DataContext - in other words you wrap the update in the way that you suggest.
The way i traditionally write business objects i usually encapsulate the "Load methods" in the BO as well; so I might have a method named LoadEmployeesAndManagers that returns a list of employees and their immediate managers (this is a contrived example) . Maybe its just me, but in my front end I'd rather see e.LoadEmployeesAndManagers() than some long LINQ statement.
Anyway, using LINQ it would probably look something like this (not checked for syntax correctness):
var emps = from e in Employees
join m in Employees
on e.ManagerEmpID equals m.EmpID
select new
{ e,
m.FullName
};
Now if I understand things correctly, if I put this in say a class library and call it from my front end, the only way I can return this is as an IEnumerable, so I lose my strong typed goodness. The only way I'd be able to return a strongly typed object would be to create my own Employees class (plus a string field for manager name) and fill it from the results of my LINQ to SQL statement and then return that. But this seems counter intuitive... what exactly did LINQ to SQL buy me if I have to do all that?
I think that I might be looking at things the wrong way; any enlightenment would be appreciated.
"the only way I can return this is as an IEnumerable, so I lose my strong typed goodness"
that is incorrect. In fact your query is strongly typed, it is just an anonymous type. I think the query you want is more like:
var emps = from e in Employees
join m in Employees
on e.ManagerEmpID equals m.EmpID
select new Employee
{ e,
m.FullName
};
Which will return IEnumerable.
Here is an article I wrote on the topic.
Linq-to-sql is an ORM. It does not affect the way that you design an N-tiered application. You use it the same way you would use any other ORM.
#liammclennan
Which will return IEnumerable. ... Linq-to-sql is an ORM. It does not affect the way that you design an N-tiered application. You use it the same way you would use any other ORM.
Then I guess I am still confused. Yes, Linq-to-Sql is an ORM; but as far as I can tell I am still littering my front end code with inline sql type statements (linq, not sql.... but still I feel that this should be abstracted away from the front end).
Suppose I wrap the LINQ statement we've been using as an example in a method. As far as I can tell, the only way I can return it is this way:
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;
}
}
From my front end code I would do something like this:
EmployeesDAL dal = new EmployeesDAL;
var emps = dal.LoadEmployeesAndManagers();
This of course returns an IEnumerable; but I cannot use this like any other ORM like you say (unless of course I misunderstand), because I cannot do this (again, this is a contrived example):
txtEmployeeName.Text = emps[0].FullName
This is what I meant by "I lose strong typed goodness." I think that I am starting to agree with Crucible; that LINQ-to-SQL was not designed to be used in this way. Again, if I am not seeing things correctly, someone show me the way :)