- Home
- LLBLGen Pro
- Architecture
Can I get a basic example of a WCF Service
Joined: 17-Aug-2003
The documentation contains a basic setup.
The docs can be unreadable (give an error) in the case of an MS security installment. This is a known issue for IE. See this faq item for details how to get it working. http://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=10965
Joined: 23-Oct-2007
Yes, I was able to get the documentation examples, thank you!
By the way, using version 2.5 Final Demo (30-Day trial) for testing on SQL Server 2005 Express and/or SQL Server 2005.
I have a working WCF Service and your concept of WCF fits right into that.
When I build the model project do I use the Adapter or SelfServicing type? I was able to VERY easily get a working object model with the SelfServicing model but can't get anything useful out of the adapter type yet. Still working through the demos of adapter type.
When I used the SelfServicing model type my parent object inheirently contained collections of its children, my adapter model doesn't seem to behave the same, am I doing something wrong?
This code works for SelfServicing but not for Adapter?:
using System; using System.Collections.Generic; using System.Text; using TowersPerrin.RiskAgility.PC.Data; using TowersPerrin.RiskAgility.PC.Data.CollectionClasses; using TowersPerrin.RiskAgility.PC.Data.EntityClasses; using TowersPerrin.RiskAgility.PC.Data.HelperClasses;
namespace PatternTestConApp { class Program { static void Main(string[] args) {
PatternCollectionCollection myCollection = new PatternCollectionCollection();
int collCount = myCollection.GetDbCount();
myCollection.GetMulti(null);
foreach (PatternCollectionEntity nextCollection in myCollection.Items)
{
Console.WriteLine("Pattern Collection Name: {0}", nextCollection.CollName);
foreach (PatternEntryEntity nextPattern in nextCollection.PatternEntry)
{
Console.WriteLine("Pattern name: {0}", nextPattern.PatternNames.PatternName);
}
}
Console.ReadLine();
}
}
}
When I try re-coding to use the DataAdapter.FetchEntity() etc. I don't see the child collections of, in this case, patternEntry.
Peter
Joined: 21-Aug-2005
RelatedEntities are fetched when accessed when you are using the SelfServicing model, that's called LazyLoading. You can stop this feature if you use PrefetchPaths
In the Adapter model, you have to use PrefetchPaths to fetch related entities upfront, or manually fetch them when you need them.
Please check the manual's section: Using the generated code -> Adapter -> Prefetch paths
Joined: 23-Oct-2007
Well, I've gotten farther but still no child collection data (though it exists in the DB). This is the code I've written so far the pattenNames collection is still empty?:
using (DataAccessAdapter myAdapter = new DataAccessAdapter(true))
{
EntityCollection myCollection =
new EntityCollection(new PatternCollectionEntityFactory());
IPrefetchPath2 prefetchPath =
new PrefetchPath2((int)EntityType.PatternCollectionEntity);
prefetchPath.Add(PatternCollectionEntity.PrefetchPathPatternEntry).SubPath.Add( PatternCollectionEntity.PrefetchPathPatternEntry);
prefetchPath.Add(PatternEntryEntity.PrefetchPathPatternNames);
IRelationPredicateBucket filter = new RelationPredicateBucket();
//filter.PredicateExpression.Add();
//DataAccessAdapter adapter = new DataAccessAdapter();
myAdapter.FetchEntityCollection(myCollection, filter, 1000);
myAdapter.FetchEntityCollection(myCollection, null);
//int collCount = myCollection.GetDbCount();
//myCollection.GetMulti(null);
foreach (PatternCollectionEntity nextCollection in myCollection)
{
Console.WriteLine("Pattern Collection Name: {0}", nextCollection.CollName);
foreach (PatternEntryEntity nextPattern in nextCollection.PatternEntry)
{
Console.WriteLine("Pattern name: {0}", nextPattern.PatternNames.PatternName);
}
}
}
Console.ReadLine();
Joined: 23-Oct-2007
I guess at this point I must ask why the object model/collection does not already know all this and why I have to perform these operations on objects that should already know their children etc. (ala the SelfServicing model)?
And also, I do not understand your response, can you give an example in code?
Peter
Joined: 21-Aug-2005
I guess at this point I must ask why the object model/collection does not already know all this and why I have to perform these operations on objects that should already know their children etc. (ala the SelfServicing model)?
They know about their related entities, but the Adapter model gives you control on when to fetch those related entities. So if you are building a multi layer application. The UI Developer who don't have access to the DBSpecific code (i.e. DataAccessAdapter), can't load the related entities by just accessing them (as in the SelfServicing).
The following comparison is copeid from the docs:
When to use which template group? Both template groups offer a wide set of functionality, but do that in a different way. This difference makes it important for you to know when to pick which template group for a given project. Below are two short lists which sum up some reasons for choosing each template group and which will help you with the decision which template group to take.
When to use SelfServicing
When the project targets a single database type. When you are not using a distributed scenario like remoting or webservices. When you need navigation through your object model in a databinding scenario and you want to load the data using lazy loading. When you don't need to extend the framework. When you like to have the persistence logic into the entity classes. When you do not require fine grained database access control, like targeting per call another database.
When to use Adapter
When the project targets multiple database types or would be able to do that in the future. When you are using a distributed scenario like remoting or webservices. When you don't need lazy loading scenarios in relation traversals. You can still navigate relations but you have to fetch the data up-front. When you need to extend the framework with derived classes. When you like to see persistence logic as a 'service', which is offered by an external object (broker, adapter). When you require fine grained database access control. When you want to convert Entities to XML and back and performance and XML size are important.
And also, I do not understand your response, can you give an example in code?
The following is an example from the docs on how to use the prefetchPath:
// C#
EntityCollection orders = new EntityCollection(new OrderEntityFactory());
IPrefetchPath2 prefetchPath = new PrefetchPath2((int)EntityType.OrderEntity);
prefetchPath.Add(OrderEntity.PrefetchPathCustomer);
IRelationPredicateBucket filter = new RelationPredicateBucket();
filter.PredicateExpression.Add(OrderFields.EmployeeId == 2));
DataAccessAdapter adapter = new DataAccessAdapter();
adapter.FetchEntityCollection(orders, filter, prefetchPath);
Joined: 23-Oct-2007
I'm sorry, but your regurgitation of the documentation isn't helping me, what did you mean by "pathing" and as far as I can see I have pathed the parent to child collection.
On a broader note though, I am evaluating your product for use by my company in our resold applications. The application may, in some cases, require the joining of hundreds of tables in a large model. If I have to code each join (pathing) before they are useful I may as well write this all myself, it saves me no time or effort.
Will I have to code each object relationship in this way in order to use WCF architecture and LLBLGen?
Peter
Joined: 01-Feb-2006
PJonesTSS wrote:
I'm sorry, but your regurgitation of the documentation isn't helping me, what did you mean by "pathing" and as far as I can see I have pathed the parent to child collection.
On a broader note though, I am evaluating your product for use by my company in our resold applications. The application may, in some cases, require the joining of hundreds of tables in a large model. If I have to code each join (pathing) before they are useful I may as well write this all myself, it saves me no time or effort.
Will I have to code each object relationship in this way in order to use WCF architecture and LLBLGen?
Peter
Peter
At a quick glance, your code defining the prefetch paths looks correct but you need to pass it to your myAdapter for it to be used - there are multiple overloads on myAdapter, just use one that accepts a Prefetch path and it should work as you expect. (Also the sample code you gave creates a filter but it is left empty and you are fetching the collection twice - but I assume this is just 'play' code)
The thing about Adapter is that the entities do know their children etc. in as much as there are properties on all the entities for their member collections.
What they don't and can't know is which child collections and child sub collections you want to bring back at any given call to a Fetch method. Frans is good but writing code for mindreading is probably beyond even him!
As you mention, you may have hundreds of tables joined in a large model. If the fetch methods assumed you wanted to bring back all of the related items then you would read the entire database into memory in one call! Thats why you need to specify which items you require (and with what filters, maximum count etc) at the time of the fetch. There is no reason you have to create the Prefetch paths at every point in the code you want to fetch a collection though, you could create a static factory class with methods which returns pre-created prefetch paths etc.
Cheers Simon
Joined: 17-Aug-2003
Simon above explains it in full .
PJonesTSS wrote:
I'm sorry, but your regurgitation of the documentation isn't helping me, what did you mean by "pathing" and as far as I can see I have pathed the parent to child collection.
On a broader note though, I am evaluating your product for use by my company in our resold applications. The application may, in some cases, require the joining of hundreds of tables in a large model. If I have to code each join (pathing) before they are useful I may as well write this all myself, it saves me no time or effort.
Sure it does. The application cant figure out based on nothing what you really want. I've reworked your code a bit below with what I meant.
Will I have to code each object relationship in this way in order to use WCF architecture and LLBLGen? Peter
No. You have to specify with prefetch paths which related entities you want to fetch ADDITIONALLY with the entities you're fetching with that query. So if you're fetching all customers from the USA, and you want also fetch their latest 10 orders, you can, in 1 call: you specify the filter for the customers, you specify the path for the orders, and you call FetchEntityCollection() and LLBLGen Pro will efficiently fetch the 2 node graph for you in 2 queries (instead of #of customers + 1 queries)
Your code which should work:
using (DataAccessAdapter myAdapter = new DataAccessAdapter(true))
{
EntityCollection myCollection = new EntityCollection(new PatternCollectionEntityFactory());
IPrefetchPath2 prefetchPath = new PrefetchPath2((int)EntityType.PatternCollectionEntity);
prefetchPath.Add(PatternCollectionEntity.PrefetchPathPatternEntry)
.SubPath.Add( PatternCollectionEntity.PrefetchPathPatternEntry);
prefetchPath.Add(PatternEntryEntity.PrefetchPathPatternNames);
// you've now specified the entity container to fill and the graph (in the prefetch path)
// you want to fetch, so the additional entities you want to get fetched with PatternCollection.
// you now pass everything to the fetch method
myAdapter.FetchEntityCollection(myCollection, filter, prefetchPath);
foreach (PatternCollectionEntity nextCollection in myCollection)
{
Console.WriteLine("Pattern Collection Name: {0}", nextCollection.CollName);
foreach (PatternEntryEntity nextPattern in nextCollection.PatternEntry)
{
Console.WriteLine("Pattern name: {0}", nextPattern.PatternNames.PatternName);
}
}
}
Console.ReadLine();
The whole entity model could be 1 connected graph with many edges. See the prefetch path as the specification which edges the fetch routine should traverse to fetch the additional related entities in the single call. As Simon explained, you don't want the complete model fetched therefore you specify it up front.
Why not lazy loading you might ask? Well, in a distributed environment, lazy loading isn't going to help, as the request is initiated on the client, but the db isn't available. Therefore you've to fetch (eager load) it up front
Joined: 23-Oct-2007
Otis, Thank you, when I put this code in place of mine I receive the following error message: "The prefetch path element at index 0 in the passed in prefetch path for root entity type 1 is meant for root entity type 0 which isn't a subtype of 1. This means that you've added a prefetch path node to a Path of an unrelated entity, for example adding OrderDetailsEntity.PrefetchPathProduct to a prefetch path for CustomerEntity."
Here is the new code in question:
using (DataAccessAdapter myAdapter = new DataAccessAdapter(true))
{
EntityCollection myCollection =
new EntityCollection(new PatternCollectionEntityFactory());
IPrefetchPath2 prefetchPath =
new PrefetchPath2((int)EntityType.PatternCollectionEntity);
prefetchPath.Add(PatternCollectionEntity.PrefetchPathPatternEntry)
.SubPath.Add(PatternCollectionEntity.PrefetchPathPatternEntry);
prefetchPath.Add(PatternEntryEntity.PrefetchPathPatternNames);
// you've now specified the entity container to fill and the graph (in the prefetch path)
// you want to fetch, so the additional entities you want to get fetched with PatternCollection.
// you now pass everything to the fetch method
IRelationPredicateBucket filter = new RelationPredicateBucket();
myAdapter.FetchEntityCollection(myCollection, filter, prefetchPath); //<-- Errors here
foreach (PatternCollectionEntity nextCollection in myCollection)
{
Console.WriteLine("Pattern Collection Name: {0}", nextCollection.CollName);
foreach (PatternEntryEntity nextPattern in nextCollection.PatternEntry)
{
Console.WriteLine("Pattern name: {0}", nextPattern.PatternNames.PatternName);
}
}
}
Console.ReadLine();
Joined: 23-Jun-2007
Hello PJonesTSS, As far as I know, your prefetch path is equivalent to :
IPrefetchPath2 prefetchPath = new PrefetchPath2((int)EntityType.PatternCollectionEntity);
prefetchPath.Add(PatternCollectionEntity.PrefetchPathPatternEntry);
prefetchPath[0].SubPath.Add( PatternCollectionEntity.PrefetchPathPatternEntry );
prefetchPath.Add(PatternEntryEntity.PrefetchPathPatternNames);
So let's have a look at this. line after line :
IPrefetchPath2 prefetchPath = new PrefetchPath2((int)EntityType.PatternCollectionEntity);
ok, you're starting from PatternCollectionEntity
prefetchPath.Add(PatternCollectionEntity.PrefetchPathPatternEntry);
so you want to fetch all the PatternEntry related to your PatternCollection Your graph now looks like
PatternCollection (prefetch path root) | | |----------- PatternEntry (prefetchPath[0])
prefetchPath[0].SubPath.Add( PatternCollectionEntity.PrefetchPathPatternEntry );
There is a problem here because you're trying to add a subpath from PatternEntry to PatternEntry itself by using the path defined in PatternCollection!
I guess that what you want to do is
PatternCollection (root) | | |-------- PatternEntry (step1) | | |---------- PatternNames ( step2)
Let's go! The first thing we have to do is to declare the starting point (PatternCollection)
IPrefetchPath2 root = new PrefetchPath2((int)EntityType.PatternCollectionEntity);
Then, you want to do the step1 (PatternCollection -> PatternEntry)
IPrefetchPathElement2 pathToStep1 = root.Add(PatternCollectionEntity.PrefetchPathPatternEntry);
And from there, you want to do the step 2 (PatternEntry -> PatternNames)
IPrefetchPathElement2 pathToStep2 = pathToStep1.SubPath.Add(PatternEntry.PrefetchPathPatternNames);
And you're done. I hope it helps
Joined: 17-Aug-2003
THanks stefcl for the detailed explanation!
Graph specification can be a little awkward at times, because a normal developer reaction is to try to specify everything on a single line, however with a branched graph, that's not doable, so you have to specify it on multiple lines: first one branch, then the other, by attaching it to the right branch start node.