Imagine the following simple LINQ query implemented using LINQ to SQL:
Domain.Base.City, Domain.Base.State, and Domain.Base.Country are C# objects defined as domain objects in our code. We translate the values from the LINQ DataContext tables and assign them to these objects as part of the query. After the query is executed, we have an IQuerable interface to a list of Domain.Base.City objects, with the State and Country sub-objects also filled. (_DCO is our LINQ DataContext object generated with SQLMetal). What we want to do is be able to separate out the code which assigns values from the _DCO.States and _DCO.Countries database tables out into methods which can be re-used in the C# code. So for example: var q = from c in _DCO.Cities select new Domain.Base.City() { ID = c.CityID, Name = c.Name, DistinctName = c.DistinctName, DisplayName = c.DisplayName, State = PopulateStateObject(c.State) }; return q.AsQueryable(); Inside PopulateStateObject() we would also have a similar call to PopulateCountryObject() which would fill all the fields. That would allow us to write one piece of code which assigned all the database table fields to the C# domain object and re-use that piece of code in multiple queries if we wanted to. The problem with LINQ-to-SQL is that it can't do this without a significant performance hit, because for some reason it can't execute it as a single SQL query. If we populate the domain objects as shown in the original call it's much faster, but moving the code into a re-usable method makes it too slow, even if that method returns IQueryable. Can your library be configured to handle a situation like this with future queries, prefetch, or something else? We'd like to have these sub-queries and pieces of LINQ-style code defined in methods which can be re-used. Thanks! |
Hello JS1, I transformed your initial query to DataObjects.Net version and got following query
This query executes as one single SQL query.
But I have noticed that you return
If we do the same thing with State and Country classes than we will be able rewrite our previous query into this
But there is one restiction - you cannot continue building IQueryable in most cases. You can continue using Linq for filtering and other things but you will have to use q.AsEnumerable()
So if whan I have done is what you need than yes DataObjects.Net can do what you want. If not, than explain me where I'm wrong and I will try to help you. Here is a simple project to play around for you. Our Community license will be enough for experiments. The link will be actual for a while. Hey Alexey... added a comment on top of yours but just realized it is posted as a response to my own question, so not sure if that alerts you or not. I am replying to your comment just in case. Thanks! Actually, one more question: unless I have missed something in your documentation, it appears as though you do not have an automatic code generation utility like SQLMetal which can be pointed at a database and automatically generate Entity objects for every table that already exists. Does a tool like that exist for SQL Server, or would we have to manually create each Entity and then map it to an existing table structure? Thanks! As far as I know Linq-to-Sql creates classes based on database structure. This method is also known as Database-First. That method makes you think in terms of tables, columns and so on. DataObjects.Net is Code-First ORM. Code-First method allows you not to thing about tables but be on OOP "field" and think in terms of classes and properties. So you develop classes and their relations and ORM creates corresponding tables , columns, foreign keys, indexes and so on based on these classes. You don't have to do any map an Entity to a database table. DataObjects.Net analyzes structure of classes and build such map by itself. DataObjects.Net Domain is ready you can open a session and transaction and perform queries, create new Entities and update them. I will add some comments about what is going on to the example project I have posted in the first comment. Thanks a lot for your response! Of course I understand that the code-first approach is what you guys will normally use, and that is what the project that you provided already does. However, what if we already have an existing database? Obviously we'd like some automatic Entity Class generation to be built based on our existing DB, much the same as SQLMetal.exe can do. Just so I am clear, is there such a tool in your solution? And if not, would you consider adding it? It is extremely useful, as not everyone can afford to start with a code-first approach when retrofitting existing projects. Unfortunately, we don't have code generation by existing database and we don't have near future plans for additing such tool. We have two legacy DomainUpgradeMode's - LegacySkip and LegacyValidate. You can use them on existing database, but you will have to implement Persistent types anyway. Also I can recommend you to use DomainUpgradeMode.Validate. You will get difference between model and database schema if any exists, it might be helpful Thanks Alexey... that's what I thought. I would suggest that you should perhaps think about this, as it would be a great selling point for your code library. Many people have existing large database installations (for example, in large corporations) that they cannot just abandon and start from scratch using a code-first approach. I would think that you could really expand your customer base if you added this tool... in the meantime, I think you have answered all my questions. Much appreciated! Hey Alexey... not sure how the comments alerts work, so I am adding a comment here too. Just to get a final answer on this: Is it fair to say that if I build a complex query with your system, using IQueryable for all the pieces, calling .ToDto() for internal parts of the query as you have shown, that when I call the final ToDto() at the end, that is where the query will actuallly get executed? And that it will have the same performance as if I had built all the Dto objects directly into the query instead of calling .ToDto() a number of times interally to build the sub-objects? Thanks! |