Can I get a basic example of a WCF Service

Posts   
 
    
PJonesTSS
User
Posts: 7
Joined: 23-Oct-2007
# Posted on: 23-Oct-2007 21:08:06   

Can I get an example of using LLBLGen as a WCF Service.

The documentation I downloaded was no readable after installation.

Kind regards,

Peter Jones

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39749
Joined: 17-Aug-2003
# Posted on: 24-Oct-2007 10:16:46   

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

Frans Bouma | Lead developer LLBLGen Pro
PJonesTSS
User
Posts: 7
Joined: 23-Oct-2007
# Posted on: 24-Oct-2007 16:03:01   

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

Walaa avatar
Walaa
Support Team
Posts: 14983
Joined: 21-Aug-2005
# Posted on: 24-Oct-2007 16:55:34   

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

PJonesTSS
User
Posts: 7
Joined: 23-Oct-2007
# Posted on: 24-Oct-2007 17:16:44   

Following the manual this line of code will not compile:

IPrefetchPath2 prefetchPath = new PrefetchPath2((int)EntityType.PatternCollectionEntity);

IPrefetchPath2 is undefined?

Peter

Walaa avatar
Walaa
Support Team
Posts: 14983
Joined: 21-Aug-2005
# Posted on: 24-Oct-2007 17:24:46   

Right click on it an select Resolve. This should add

using SD.LLBLGen.Pro.ORMSupportClasses;

To the top of your code file. (Which you can add manually)

PJonesTSS
User
Posts: 7
Joined: 23-Oct-2007
# Posted on: 24-Oct-2007 17:40:21   

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();
Walaa avatar
Walaa
Support Team
Posts: 14983
Joined: 21-Aug-2005
# Posted on: 24-Oct-2007 18:15:35   

You need to path the prefetchPath to the FetchEntityCollection() method.

PJonesTSS
User
Posts: 7
Joined: 23-Oct-2007
# Posted on: 24-Oct-2007 18:31:49   

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

Walaa avatar
Walaa
Support Team
Posts: 14983
Joined: 21-Aug-2005
# Posted on: 24-Oct-2007 18:41:14   

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);
PJonesTSS
User
Posts: 7
Joined: 23-Oct-2007
# Posted on: 24-Oct-2007 18:55:47   

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

simmotech
User
Posts: 1024
Joined: 01-Feb-2006
# Posted on: 25-Oct-2007 06:23:13   

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

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39749
Joined: 17-Aug-2003
# Posted on: 25-Oct-2007 11:33:19   

Simon above explains it in full simple_smile .

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 simple_smile

Frans Bouma | Lead developer LLBLGen Pro
PJonesTSS
User
Posts: 7
Joined: 23-Oct-2007
# Posted on: 26-Oct-2007 20:59:11   

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();
stefcl
User
Posts: 210
Joined: 23-Jun-2007
# Posted on: 26-Oct-2007 23:03:00   

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

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39749
Joined: 17-Aug-2003
# Posted on: 27-Oct-2007 14:04:36   

THanks stefcl for the detailed explanation! simple_smile

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.

Frans Bouma | Lead developer LLBLGen Pro