Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom implementation of a DomainService using Linq to SQL

Can anyone point me to an example of or briefly describe how one would go about creating a custom implementation of a WCF RIA Services DomainService using Linq to SQL as the data access layer but without the use of the .dbml file (this is because the Linq to SQL model is generated by a custom tool, is heavily cutomized, and is of a fairly large database with 50+ tables) and without the VS2010 wizard for creating a DomainService (the wizard is dependant on the .dbml file being available)

Here's a really simple shell of what I tried myself so far:

[EnableClientAccess()]
public class SubscriptionService : DomainService
{
    [Query(IsDefault = true)]
    public IQueryable<Subscription> GetSubscriptionList()
    {
        SubscriptionDataContext dc = new SubscriptionDataContext();
        var subs = dc.Subscription.Where(x => x.Status == STATUS.Active)
            .Select(x => 
            new Subscription
            {
                ID = x.ID,
                Name = x.Name
            }).ToList();

        return subs.AsQueryable();
    }

    public void InsertSubscription(Subscription sub)
    {
        if (!sub.ID.IsEmpty())
        {
            SubscriptionDataContext dc = new SubscriptionDataContext();
            Subscription tmpSub = dc.GetByID<Subscription>(sub.ID);
            if (tmpSub != null)
            {
                tmpSub.Name = sub.Name;
                dc.Save(tmpSub);
            }
            else
            {
                tmpSub = new Subscription();
                tmpSub.Name = sub.Name;
                dc.Save(tmpSub);
            }
        }
    }

    public void UpdateSubscription(Subscription sub)
    {
        if (!sub.ID.IsEmpty())
        {
            SubscriptionDataContext dc = new SubscriptionDataContext();
            Subscription tmpSub = dc.GetByID<Subscription>(sub.ID);
            if (tmpSub != null)
            {
                tmpSub.Name = sub.Name;
                dc.Save(tmpSub);
            }
        }
    }

    public void DeleteSubscription(Subscription sub)
    {
        if (!sub.ID.IsEmpty())
        {
            SubscriptionDataContext dc = new SubscriptionDataContext();
            Subscription tmpSub = dc.GetByID<Subscription>(sub.ID);
            if (tmpSub != null)
            {
                dc.Delete(tmpSub);
            }
        }
    }
}

This seems to work so far. Does anyone see any problem with this approach that I might be missing? I don't want to go too far down the wrong road with this if someone has already tried this way and found some major problems with it.

Thanks for everyone's input.

like image 858
Dmitry Samuylov Avatar asked Aug 31 '11 20:08

Dmitry Samuylov


1 Answers

There is nothing wrong with doing it this way.

I've done basically the same thing.

you will need to create a property that returns an IQueryable for each query, and you will auto-magically get the skip/take/where stuff with RIA Services.

[EnableClientAccess()]
public class SubscriptionService : DomainService
{
    [Query(IsDefault = true)]
    public IQueryable<Subscription> GetSubscriptionList()
    {
        using(var dc = new SubscriptionDataContext())
             return from x in dc.Subscription
                    where x.Status == STATUS.Active
                    select new Subscription { ID = x.ID, Name = x.Name };
        // make sure you don't call .ToList().AsQueryable() 
        // as you will basically load everything into memory, 
        // which you don't want to do if the client is going to be using 
        // any of the skip/take/where features of RIA Services.  
        // If you don't want to allow this, 
        // simply return an IEnumerable<Subscription>
    }
 }

I assume that Subscription is a DTO and not a L2S class because you are instantiating it explicitly. Just make sure you DTOs have the correct attributes. i.e.

public class Subscription
{
    [Key]
    // you must have a key attribute on one or more properties...
    public int ID { get; set; }
}

If you have child elements in your DTO, use the Include and Association attributes :

public class User
{
    [Key]
    public int Id { get; set; }

    [Include]
    [Association("User_Subscriptions", "Id","UserId")]
    // 'Id' is this classes's Id property, and 'UserId' is on Subscription
    // 'User_Subscriptions' must be unique within your domain service,
    // or you will get some odd errors when the client tries to deserialize
    // the object graph.
    public IEnumerable<Subscription> Subscriptions { get; set; }
}

Also as a side note, you don't need the full object for your delete method, something like this would work and would keep the client from serializing the whole object and posting it back when you don't need too.

public void DeleteSubscription(int id)
{
    using(var dc = new SubscriptionDataContext())
    {
        var sub = dc.GetById<Subscription>(id);
        if( sub != null ) dc.Delete(sub);
    }
}
like image 55
Master Morality Avatar answered Nov 09 '22 22:11

Master Morality