Configuring IQueryable <T>

I am trying to configure the entities of my application so that they have a property that references the DataContext that loaded them.

I think the best way is to create a class that implements IQueryable and set the object's datacontext property in its GetEnumerator method.

My question is, how can I use the provider and expression used by Linq to SQL in my IQueryable implementation, so I don’t need to implement them myself?

By the way: is there a different way for my script?

Take a look at the following code:

public partial class Product: IEntityBase  
{ 

    public Product() 
    { 
        _DataContext = new SampleDataContext(); 
    } 

    private long _Id;  
    [Column(Storage="_Id", AutoSync=AutoSync.OnInsert, DbType="BigInt NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true)]  
    public long Id  
    {  
         get{ return _Id; }  
         set{ _Id = value; }  
    }  

    private string _Name;  
    [Column(Storage="_Name", DbType="NVarChar(MAX) NOT NULL", CanBeNull=false  
    public string Name  
    {  
        get{ return _Name; }  
        set{ _Name = value; }  
    }  

    private SampleDataContext _DataContext;  

    //This is the property extending the Product class and should be set when this class is being returned 
    //by IQueryable<T>.GetEnumerator() 
    public SampleDataContext DataContext  
    {  
        get{ return _Name; }  
        set{ _Name = value; }  
    }  

    public MyQueryable<Product> GetProducts() 
    { 
        MyQueryable<Product> result = from p in context.Products 
                                      where {Some Conditions 1} 
                                      select p; 
        result.DataContext = _DataContext; 
        return result; 
    } 

    public void SomeMethod() 
    { 
        //This query will not actually set the DataCotnext property. 
        //And the generated sql query is something like:  
        //SELECT * FROM Products WHERE {Some Conditions 1} AND {Some Conditions 2} 
        var products = GetProducts().Where( {Some Conditions 2} ); 

        //Now that the GetEnumerator() is called the DataContext property of the products 
        //will be set. 
        foreach( var item in products ) 
        { 
            item.Name = "Test Name"; 
            item.DataContext.SubmitChanges(); 
        } 
    } 
}  

public MyQueryable<T>: IQueryable<T> 
    where T: class, IEntityBase 
{ 
    // 
    //Implementation of IQueryable which is my question 
   // 

   public IEnumerator<T> GetEnumerator() 
   { 
       foreach( var item in Provider.GetEnumerator<T>() ) 
       { 
            item.DataContext = this.DataContext; 
            yield return item; 
       } 
   } 

   public SampleDataContext DataContext{ get; set; } 
} 

public interface IEntityBase 
{ 
    SampleDataContext DataContext{ get; set; }; 
} 

UPDATE

I myself found the answer. Here is a sample code to show how I did it.

public MyQueryable<T, TContext>: IQueryable<T> 
    where T: class, IEntityBase 
    where TContext: DataContext, new()
{ 

   public MyQueryable<T>(TContext context, IQueryable<T> baseIQueryable)
   {
        if( baseIQueryable == null )
            throw new ArgumentNullException("baseIQueryable");

        this.Provider = baseIQueryable.Provider;            
        this.Expression = baseIQueryable.Expression;

        this.DataContext = context;
   }

   public IEnumerator<T> GetEnumerator()
   {
       var enumerator = Provider.Execute<IEnumerable<T>>(Expression);
       foreach( var item in enumerator )
       {
           item.DataContext = this.DataContext ?? new TContext();
           yield return item;
       }
   }

   IEnumerator IEnumerable.GetEnumerator()
   {
       var enumerator = Provider.Execute<IEnumerable>(Expression);
       foreach( var item in enumerator )
       {
           ((IEntityBase<TContext>)item).DataContext = this.DataContext;
           yield return item;
       }
   } 

   //
   //Other implementations...
   //
   public SampleDataContext DataContext{ get; set; } 
} 

public partial class Product: IEntityBase
{
    public MyQueryable<Product> GetProducts() 
    { 
        var result = from p in context.Products 
                     where {Some Conditions 1} 
                     select p; 
        return new MyQueryable<typeof(Product), DataContext>(this.DataContext, result);
    }         
}
+3
source share
2 answers

. LINQ-to-SQL, . LINQ-to-Objects:

public IEnumerable<Product> GetProducts() 
{ 
    IQueryable<Product> result = from p in context.Products 
                                  where {Some Conditions 1} 
                                  select p; 
    return result.AsEnumerable().Select( x => {
       x.SomeProp = context;
       return x;
    });
}

, - - LINQ-to-Objects.

/ , ( ):

   return result.AssociateWith(context);

- :

public static IEnumerable<T> AssociateWith<T>(
        this IEnumerable<T> source,
        DataContext context)
    where T : IEntityBase
{
    foreach(T item in source)
    {
        item.DataContext = context;
        yield return item;
    }
}
+1

The Wayward Weblog IQueryable toolkit. , , .

, , LINQ SQL-, Active Record, , GetById, Query, Insert, Update Delete . , .

DataContext , .

0

Source: https://habr.com/ru/post/1702353/


All Articles