Home > Mobile >  EF 6 and SQL to LINQ?
EF 6 and SQL to LINQ?

Time:07-13

I'm trying to convert my SQL statement into .NET Core 6 C# syntax rather than using .FromSqlRaw.

I've review LINQ doc but the don't seem to cover the join scenario I need and the documentation doesn't actually describe the process.

SELECT        dbo.TRIGGERS.trgID, dbo.TRIGGERS.atvID, dbo.TRIGGERS.trgEvent, dbo.TRIGGERS.trgIsDeleted
FROM            dbo.CLIENTFACILITYTRIGGERS INNER JOIN
                         dbo.TRIGGERS ON dbo.CLIENTFACILITYTRIGGERS.trgID = dbo.TRIGGERS.trgID
WHERE        (dbo.CLIENTFACILITYTRIGGERS.cltID = 1) AND (dbo.CLIENTFACILITYTRIGGERS.facID = 1)

CLIENTFACILITYTRIGGERS is a table with composite key on it's 3 field cltID facID trgID

TRIGGERS has a single primary key (trgID) trgID atvID trgEvent trgIsDeleted

Simple query, get all TRIGGERS for a given cltId and facID.

I'm not having much luck converting this to .NET 6 Core C# LINQ. Or, point me to a good resource (not Microsoft's documentation and not automatic converters) that explain how to convert SQL into .NET 6 Core C# LINQ? I want to learn, not mimic.

CodePudding user response:

You don't need JOINs if your classes have proper relations. ORMs like Entity Framework allow you to work with classes, not tables. If you have a ClientFacility class with a Triggers collection, EF itself will generate the proper JOINs when you load a ClientFacility.

The Relationships article in the EF Core documentation shows how to define relationships in general so you don't have to deal with keys and JOINs in queries.

The Blog/Posts example shows how to handle 1:M relations:

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    public List<Post> Posts { get; set; }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    public string Title {get;set;}
    
    public int BlogId { get; set; }
    public Blog Blog { get; set; }
}

With these classes, if you want to find all the posts of a blog you can write :

var posts=_context.Posts.Where(p=>p.Blog.Title="Bananas");

It's EF's job to generate the Blogs INNER JOIN Posts ON Blogs.BlogID=Posts.BlogId clause.

In the question's case it seems there's a many-to-many relation between ClientFacility and Trigger. EF Core 6 allows modelling many-to-many relations without also modelling the bridge class ClientFacilityTrigger.

Assuming you have :

public class ClientFacility
{
    public long ClientFacilityId {get;set;}

    public List<Trigger> Triggers {get;set}
}

public class Trigger
{
   public long TriggerId {get;set;}

   public string Event {get;set;}
   public bool IsDeleted {get;set;}
}

public class MyContext:DbContext
{
    public DbSet<Facility> Facilities {get;set;}
    public DbSet<Trigger> Triggers {get;set;}
}

You could retrieve a facility's triggers with :

var results=from facility in _context.Facilities
            where facility.ClientFacilityId=1
            from trigger in facility.Triggers
            select new {
                trigger.Event,
                trigger.IsDeleted,
                ...
            };

A DbContext's OnModelBuilding method can be used to define more complex relations, eg using composite keys or columns that don't follow naming conventions.

This clause makes me suspect there are more entities, Client and Facility and ClientFacility links them to Trigger. This can be modelled as well :

public class Client
{
    public long ClientId {get;set;}

    public List<ClientFacility> Facilities {get;set;}
}

public class Facility
{
    public long FacilityId {get;set;}

    public List<ClientFacility> Facilities {get;set;}
}

public class ClientFacility
{
    public long ClientFacilityId {get;set;}

    public long ClientId {get;set;}
    public long FacilityId {get;set;}

    public Client Client{get;set;}
    public Facility Facility {get;set;}
}

CodePudding user response:

This should work for you, just use your context and the entities related to your tables (change this: context.CLIENTFACILITYTRIGGERS and this: context.TRIGGERS)

var query = 
    from cft in context.CLIENTFACILITYTRIGGERS 
    join t in context.TRIGGERS on cft.trgID equals t.trgID
    where cft.cltID == 1 && cft.facID == 1
    select new 
    {
        TrgId = t.trgID, 
        AtvId = t.atvID, 
        TrgEvent = t.trgEvent, 
        TrgIsDeleted = t.trgIsDeleted
    };
  • Related