Factor out common LINQ elements (linqconect)

Discussion of open issues, suggestions and bugs regarding ADO.NET provider for PostgreSQL
Post Reply
drysg
Posts: 28
Joined: Fri 09 Mar 2012 15:10

Factor out common LINQ elements (linqconect)

Post by drysg » Fri 04 May 2012 14:19

If you look at the code below, you see a great deal of repetition in reading and extracting the values from a LinqQuery Table. It is easy enough to create a function that would accept a dotconnect context model (in this case the context is GPL, and the context Model is GPL.GPLModel), but what about the c.Type, c.Creator, c.Distributor, c.Handling). I have looked all through the methods of GPL.GPLModel (created by LinqConnect, but I am still not getting it.

As you can see, I was able to factor out some code into the private makeResponse method.

Code: Select all

 private ItemList makeResponse(IEnumerable<Item> data)
        {
            Item[] results = data.ToArray<Item>();
            ItemList response = new ItemList
            {
                count = results.Length,
                results = results
            };
            return response;
        }

        public ItemList Mcreators()
        {
            GPL.GPLModel context = new GPL.GPLModel();
            var rows =
                from c in context.MCreators
                select new Item
                {
                    idx = c.Idx,
                    name = c.Creator
                };
            return makeResponse(rows);
        }

        public ItemList Mtypes()
        {
            GPL.GPLModel context = new GPL.GPLModel();
            var rows =
                from c in context.MTypes
                select new Item
                {
                    idx = c.Idx,
                    name = c.Type
                };
            return makeResponse(rows);
        }


        public ItemList Mhandlings()
        {
            GPL.GPLModel context = new GPL.GPLModel();
            var rows =
                from c in context.MHandlings
                select new Item
                {
                    idx = c.Idx,
                    name = c.Handling
                };
            return makeResponse(rows);
        }

        public ItemList Mdistributors()
        {
            GPL.GPLModel context = new GPL.GPLModel();
            var rows =
                from c in context.MDistributors
                select new Item
                {
                    idx = c.Idx,
                    name = c.Distributor
                };
            return makeResponse(rows);
        }

        public ItemList McolumnNames()
        {
            PropertyInfo[] propertyInfos;
            propertyInfos = typeof(CatalogEntry).GetProperties(BindingFlags.Public | BindingFlags.Instance);
            int id = 0;
            var rows =
                from p in propertyInfos
                select new Item
                {
                    idx = id++,
                    name = p.Name
                };
            return makeResponse(rows);
        }

MariiaI
Devart Team
Posts: 1472
Joined: Mon 13 Feb 2012 08:17

Re: Factor out common LINQ elements (linqconect)

Post by MariiaI » Tue 08 May 2012 13:32

Could you please specify the definitions of the classes used in the sample and describe the scenario you are trying to implement?
As far as I can understand, the Item class has two properties ('ID' and 'Name') which you are trying to extract from entities of other types. Am I correct? If yes, you can try performing the following steps to do so:
- make the private fields corresponding to ID and Name protected;
- inherit other classes ("MDistributor" etc.) from the "Item" class;
- change inherited classes so that they use the fields of Item; for example, if the field used for 'Name' is called 'name', the MCreator.Creator property may be implemented as follows:

Code: Select all

class MCreator : Item  {
public string Creator {
  get { return name; }
  set { name = value; }
}}
- change the storage members of the inherited classes' properties:

Code: Select all

[Column(Name = @"""Creator""", Storage = "name", DbType = "VARCHAR(40)")]
Please tell us if this helps.

drysg
Posts: 28
Joined: Fri 09 Mar 2012 15:10

Re: Factor out common LINQ elements (linqconect)

Post by drysg » Tue 08 May 2012 13:47

I did not want to burden you with all the code and class definitions. So I apologize for being too brief. (I have enclosed the project to you in email previously, and I am resending via that channel).

Item and ItemList are public classes for holding data that is to be serialized via JSON by WCF .NET services. (i.e. DataContracts)

Code: Select all

[DataContract]
    public class ItemList
    {
        int _count;
        Item[] _results;

        [DataMember]
        public int count
        {
            get { return _count; }
            set { _count = value; }
        }

        [DataMember]
        public Item[] results
        {
            get { return _results; }
            set { _results = value; }
        }
    }

    [DataContract]
    public class Item
    {
        int _idx;
        String _name;

        [DataMember]
        public int idx
        {
            get { return _idx; }
            set { _idx = value; }
        }

        [DataMember]
        public String name
        {
            get { return _name; }
            set { _name = value; }
        }
    }
}
Mccreators, Mtypes, Mhandling etc. cannot inherit from Item or ItemList. These are classes created by your LinqConnect. In the snippet below: GPL is the namespace I gave the dataContext and GPLModel is the DataContext. context.MTypes is a class mapped to a DotConnnect LinqConnect Table that was created with LinqConnect. It does not inherit from Item.

Code: Select all

        public ItemList Mtypes()
        {
            GPL.GPLModel context = new GPL.GPLModel();
            var rows =
                from c in context.MTypes
                select new Item
                {
                    idx = c.Idx,
                    name = c.Type
                };
            return makeResponse(rows);
        }

MariiaI
Devart Team
Posts: 1472
Joined: Mon 13 Feb 2012 08:17

Re: Factor out common LINQ elements (linqconect)

Post by MariiaI » Thu 10 May 2012 09:36

To solve your task with the extracting Item class properties ('ID' and 'Name') from entities of other types, you could try to change the LinqConnect Template specifically for this goal.

For more information about templates see in Entity Developer documentation:
User Interface Reference->Template Editor-> Basic Operations With Templates

drysg
Posts: 28
Joined: Fri 09 Mar 2012 15:10

Re: Factor out common LINQ elements (linqconect)

Post by drysg » Thu 10 May 2012 13:55

Cute,

So it seems that the best way would be to extend each Template to provide a generic property called name that would fetch either c.Type, c.Owner, etc. - i.e. I would extend the each class to provide a generic property.

The only issue here is that the work involved in extending the Template is more than leaving the code unfactored. (see below) so I suggest for your future work, to create a helper method to your <TABLE> class that uses introspection and reflection to allow me to add methods on the fly:

e.g. Table.addMethod("methodName", delegate, parameter array) and then execute this as a closure in the context of the Table (so that I can get to the properties of the TABLE instance and also refer to "this" properly).

What is shown below is what I see as too much work (and too prone to errors)

Code: Select all

Copy Code 
<#
// Empty template for Devart Entity Developer C# code generation.
// Copyright (c) 2008-2012 Devart. All rights reserved.
#>
<#@ template language="C#" #>
<#@ extended name="Load" owner="RelationProperty" type="System.Boolean" default="true" #>
<#
// Settings
  output.Extension = ".cs";
  output.FileName = model.FileName + "DataLoadOptionsFactory";
#>
using Devart.Data.Linq;
using Domain;

namespace <#=!string.IsNullOrEmpty(model.ContextNamespace) ? codeProvider.GetValidIdentifier(model.ContextNamespace) : codeProvider.GetValidIdentifier(model.Name)#> {

  public static class DataLoadOptionsFactory {
    
    public static DataLoadOptions CreateLoadOptions() {

       DataLoadOptions loadOptions = new DataLoadOptions();
<#
  foreach (Class cls in model.Classes)
    foreach (RelationProperty relationProperty in cls.RelationProperties)
      if ((bool)relationProperty.GetProperty("Load")) {
#>
       loadOptions.LoadWith<<#= cls.Name #>>(c => c.<#= relationProperty.Name #>);
<#
      }
#>
       return loadOptions;
    } 
  }
}
 

drysg
Posts: 28
Joined: Fri 09 Mar 2012 15:10

Re: Factor out common LINQ elements (linqconect)

Post by drysg » Thu 10 May 2012 16:09

I.e. I am looking at creating an extension to your Table<TEntity> type you created for me in LinqConnect: which is called GPL.MType:

Code: Select all

namespace GPLExtension
{
    public static class GPLAddOnMethods
    {
        public static string getName(this GPL.MType me)
        {
            return me.Type;
        }
    }
}
This provides a generic way of getting the name, but I am still looking for a way of passing in the GPL.GPLModel in a generic way?

Code: Select all

private getvalues(Table<TEntity> table) {

for rows = from c in table
                select new Item
                {
                    idx = c.Idx,
                    name = c.getName();
                };

MariiaI
Devart Team
Posts: 1472
Joined: Mon 13 Feb 2012 08:17

Re: Factor out common LINQ elements (linqconect)

Post by MariiaI » Fri 11 May 2012 10:16

To work with these entities uniformly, you can extract a common interface from them (say, 'IItem') with properties "ItemId" and "ItemName".
Specify that the entities implement this interface in the model (click on model canvas and in LinqConnectContextModel Properties set the Entity Base property to the interface IItem).
The interface implementation needs to be done for each class separately, but it does not require changing the generated code, because entity classes are partial.

With the interface IItem method GetItems can be done as generic.
We've sent you a sample project. Please check that it is not blocked by your mail filter.

drysg
Posts: 28
Joined: Fri 09 Mar 2012 15:10

Re: Factor out common LINQ elements (linqconect)

Post by drysg » Mon 14 May 2012 15:27

This works fine. I was getting too C# V4 ish. I trying out dynamic types, Class Extensions, and the like. Which was interfering with the simple Interface based way of dealing with this polymorphism.

(My issue is that I am doing more and more javascript and losing my ability to think in terms of strongly typed languages).

MariiaI
Devart Team
Posts: 1472
Joined: Mon 13 Feb 2012 08:17

Re: Factor out common LINQ elements (linqconect)

Post by MariiaI » Tue 15 May 2012 08:24

Glad to see that the problem was resolved.

Post Reply