Use common linq expression to avoid duplicate of entity to poco - linq

How may I avoid to duplicate the code I use for mapping a database entity to a poco object?
Given this code:
private IQueryable<DummyExtended> Find()
{
return (from dt in Entities.dummy_table
select new DummyExtended
{
Description = dt.table_1.table_2.description,
Dummy = new Dummy
{
Name = d.name,
Notes = d.notes,
HelpText = d.help_text
}
}).AsQueryable();
}
Can I create a common linq expression to be re-used for both methods?
private IQueryable<DummyExtended> Find()
{
return (from dt in Entities.dummy_table
select new DummyExtended
{
Description = dt.table_1.table_2.description,
Dummy = ...???
}).AsQueryable();
}
private IQueryable<DummyAlsoExtended> FindAnother()
{
return (from dt in Entities.dummy_table
select new DummyAlsoExtended
{
InnerHtml = dt.table_html.description,
Dummy = ....??
}).AsQueryable();
}
Example:
public static Expression<Func<dummy_table, Dummy>> EntityToPoco()
{
return d => new Dummy
{
Name = d.name,
Notes = d.notes,
HelpText = d.help_text
};
}
I can't quite get it right
....
Dummy = ExtensionClass.EntityToPoco()

So you have a dummy_table which is a Enumerable or Queryable sequence of objects. Let's assume that the sequence contains objects of class DummyTableElement.
You showed, that if you have a DummyTableElement you know how to convert it into a Dummy object. You want to reuse this function to create other objects like DummyExtended and DummyAlsoExtended. If you want to do this LINQ-alike, it is best to create extension functions for it:
static class DummyTableElementExtensions
{
public static Dummy ToDummy(this TableElement tableElement)
{
return new Dummy()
{
Name = tableElement.name,
Notes = tableElement.notes,
HelpText = tableElement.help_text
};
}
}
Once you have this, you can create similar functions to convert TableElements into DummyExtended and DummyAlsoExtended. They will be one-liners.
In the same extension class:
public static DummyExtended ToDummyExtended(this TableElement tableElement)
{
return new DummyExtended()
{
Description = tableElement.table_1.table_2.description,
Dummy = tableElement.ToDummy(),
};
}
public static DummyAlsoExtended ToDummyAlsoExtended(this TableElement tableElement)
{
return new DummyAlsoExtended
{
InnerHtml = tableElement.table_html.description,
Dummy = tableElement.ToDummy(),
};
}
And once you've got these, you can create extension functions to convert any IQueryable of TableElements:
public static IQueryable<DummyExtended> ToDummyExtended(
this IQueryable<TableElement> tableElements)
{
return tableElements
.Select(tableElement => tableelement.ToDummyExtended();
}
And a similar one-line function for DummyAlsoExtended.
Your Find function and FindAnother function will also be one-liners:
private IQueryable<DummyExtended> Find()
{
return dummy_table.ToDummyExtended();
}
private IQueryable<DummyAlsoExtended> FindAnother()
{
return dummy_table.ToDummyAlsoExtended();
}
I'm not sure why you wanted to use an expression in this. It doesn't seem that DummyExtended and DummyAlsoExtended are really similar, except that they both have a property Dummy.
One reason to parameterize the destination of your find function could be because you want to create anonymous classes in your Find function.
Again, once you've created ToDummy this will be a one-liner:
public static IQueryable<TResult> Find<TSource, TResult>(
this IQueryable<TSource> source,
Expression<Func<TSource, TResult>> resultSelector)
{
return source.Select(sourceElement => resultSelector(sourceElement);
}
Usage would be:
var X = dummy_Table.find(tableElement => new
{
foo = tableElement.CalculateFoo(),
bar = tableElement.CalculateBar(),
Dummy = tableElement.ToDummy(),
});

Related

How to select multiple class properties in LINQ Expression?

If I have a class like this
`
class Person
{
public string First;
public string Last;
public bool IsMarried;
public int Age;
}`
Then how can I write a LINQ Expression where I could select properties of a Person. I want to do something like this (user can enter 1..n properties)
SelectData<Person>(x=>x.First, x.Last,x.Age);
What would be the input expression of my SelectData function ?
SelectData(Expression<Func<TEntity, List<string>>> selector); ?
EDIT
In my SelectData function I want to extract property names and then generate SELECT clause of my SQL Query dynamically.
SOLUTION
Ok, so what I have done is to have my SelectData as
public IEnumerable<TEntity> SelectData(Expression<Func<TEntity, object>> expression)
{
NewExpression body = (NewExpression)expression.Body;
List<string> columns = new List<string>();
foreach(var arg in body.Arguments)
{
var exp = (MemberExpression)arg;
columns.Add(exp.Member.Name);
}
//build query
And to use it I call it like this
ccc<Person>().SelectData(x => new { x.First, x.Last, x.Age });
Hopefully it would help someone who is looking :)
Thanks,
IY
I think it would be better to use delegates instead of Reflection. Apart from the fact that delegates will be faster, the compiler will complain if you try to fetch property values that do not exist. With reflection you won't find errors until run time.
Luckily there is already something like that. it is implemented as an extension function of IEnumerable, and it is called Select (irony intended)
I think you want something like this:
I have a sequence of Persons, and I want you to create a Linq
statement that returns per Person a new object that contains the
properties First and Last.
Or:
I have a sequence of Persns and I want you to create a Linq statement
that returns per Person a new object that contains Age, IsMarried,
whether it is an adult and to make it difficult: one Property called
Name which is a combination of First and Last
The function SelectData would be something like this:
IEnumerable<TResult> SelectData<TSource, TResult>(this IEnumerable<TSource> source,
Func<TSource, TResult> selector)
{
return source.Select(selector);
}
Usage:
problem 1: return per Person a new object that contains the
properties First and Last.
var result = Persons.SelectData(person => new
{
First = person.First,
Last = person.Last,
});
problem 2: return per Person a new object that contains Age, IsMarried, whether he is an adult and one Property called Name which is a combination
of First and Last
var result = Persons.SelectData(person => new
{
Age = person.Name,
IsMarried = person.IsMarried,
IsAdult = person.Age > 21,
Name = new
{
First = person.First,
Last = person.Last,
},
});
Well let's face it, your SelectData is nothing more than Enumerable.Select
You could of course create a function where you'd let the caller provide a list of properties he wants, but (1) that would limit his possibilities to design the end result and (2) it would be way more typing for him to call the function.
Instead of:
.Select(p => new
{
P1 = p.Property1,
P2 = p.Property2,
}
he would have to type something like
.SelectData(new List<Func<TSource, TResult>()
{
p => p.Property1, // first element of the property list
p -> p.Property2, // second element of the property list
}
You won't be able to name the returned properties, you won't be able to combine several properties into one:
.Select(p => p.First + p.Last)
And what would you gain by it?
Highly discouraged requirement!
You could achive similar result using Reflection and Extension Method
Model:
namespace ConsoleApplication2
{
class Person
{
public string First { get; set; }
public string Last { get; set; }
public bool IsMarried { get; set; }
public int Age { get; set; }
}
}
Service:
using System.Collections.Generic;
using System.Linq;
namespace Test
{
public static class Service
{
public static IQueryable<IQueryable<KeyValuePair<string, object>>> SelectData<T>(this IQueryable<T> queryable, string[] properties)
{
var queryResult = new List<IQueryable<KeyValuePair<string, object>>>();
foreach (T entity in queryable)
{
var entityProperties = new List<KeyValuePair<string, object>>();
foreach (string property in properties)
{
var value = typeof(T).GetProperty(property).GetValue(entity);
var entityProperty = new KeyValuePair<string, object>(property, value);
entityProperties.Add(entityProperty);
}
queryResult.Add(entityProperties.AsQueryable());
}
return queryResult.AsQueryable();
}
}
}
Usage:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Test
{
class Program
{
static void Main(string[] args)
{
var list = new List<Person>()
{
new Person()
{
Age = 18,
First = "test1",
IsMarried = false,
Last = "test2"
},
new Person()
{
Age = 40,
First = "test3",
IsMarried = true,
Last = "test4"
}
};
var queryableList = list.AsQueryable();
string[] properties = { "Age", "Last" };
var result = queryableList.SelectData(properties);
foreach (var element in result)
{
foreach (var property in element)
{
Console.WriteLine($"{property.Key}: {property.Value}");
}
}
Console.ReadKey();
}
}
}
Result:
Age: 18
Last: test2
Age: 40
Last: test4

return list from linq function

I want to return list of typenames from the class ApplicaitonType but i recieve error
Error 1 Instance argument: cannot convert from 'System.Linq.IQueryable' to 'System.Collections.Generic.IEnumerable' C:\Users\sharaman\documents\visual studio 2010\Projects\IssueTracking\BAL_IssueTracking\AppQuery.cs 19 17 BAL_IssueTracking
Please provide your feed back on it...much appericated
public static List AppType()
{
List<ApplicationType> m = new List<ApplicationType>();
var context = new Dll_IssueTracking.IssuTrackingEntities();// Object context defined in Dll_IssuTracking DLL
var query = from c in context.ApplicationTypes//Query to find TypeNames
select new { c.TypeName };
//return query.ToList<ApplicationType>();
m = query.ToList<ApplicationType>();//Error here
return m;
}
Your query selects a sequence of an anonymous type:
select new { c.TypeName };
It's not clear how you're expecting to turn that anonymous type into an ApplicationType.
Given your data source name, I'd expect the method to be as simple as:
public static List<ApplicationType> AppType()
{
using (var context = new Dll_IssueTracking.IssuTrackingEntities())
{
return context.ApplicationTypes.ToList();
}
}
In particular, it's pointless to create an instance of List<ApplicationType> and then ignore it, as you currently do:
List<ApplicationType> m = new List<ApplicationType>();
...
m = query.ToList<ApplicationType>();
return m;
Why would you bother with the variable here, and why would you assign a value to it which you never use?
EDIT: From your comment:
Actually I need to return TypeNames from ApplicaitonType class and bind to Dropdownlist through this function
That suggests your method is declared inappropriately. Either you can return a List<ApplicationType> and specify TypeName as the display part in the data binding, or you can change your method to return a List<string> (assuming that's the type of TypeName):
public static List<string> GetApplicationTypeNames()
{
using (var context = new Dll_IssueTracking.IssuTrackingEntities())
{
return context.ApplicationTypes.Select(type => type.typeName)
.ToList();
}
}
try with this code
public static List<ApplicationType> AppType()
{
var context = new Dll_IssueTracking.IssuTrackingEntities();// Object context defined in Dll_IssuTracking DLL
var query = from c in context.ApplicationTypes//Query to find TypeNames
select new ApplicationType{TypeName = c.TypeName };
return query.ToList();
}

Entity Framework, Code First and Full Text Search

I realize that a lot of questions have been asked relating to full text search and Entity Framework, but I hope this question is a bit different.
I am using Entity Framework, Code First and need to do a full text search. When I need to perform the full text search, I will typically have other criteria/restrictions as well - like skip the first 500 rows, or filter on another column, etc.
I see that this has been handled using table valued functions - see http://sqlblogcasts.com/blogs/simons/archive/2008/12/18/LINQ-to-SQL---Enabling-Fulltext-searching.aspx. And this seems like the right idea.
Unfortunately, table valued functions are not supported until Entity Framework 5.0 (and even then, I believe, they are not supported for Code First).
My real question is what are the suggestions for the best way to handle this, both for Entity Framework 4.3 and Entity Framework 5.0. But to be specific:
Other than dynamic SQL (via System.Data.Entity.DbSet.SqlQuery, for example), are there any options available for Entity Framework 4.3?
If I upgrade to Entity Framework 5.0, is there a way I can use table valued functions with code first?
Thanks,
Eric
Using interceptors introduced in EF6, you could mark the full text search in linq and then replace it in dbcommand as described in http://www.entityframework.info/Home/FullTextSearch:
public class FtsInterceptor : IDbCommandInterceptor
{
private const string FullTextPrefix = "-FTSPREFIX-";
public static string Fts(string search)
{
return string.Format("({0}{1})", FullTextPrefix, search);
}
public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
{
}
public void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
{
}
public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
{
RewriteFullTextQuery(command);
}
public void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
{
}
public void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
{
RewriteFullTextQuery(command);
}
public void ScalarExecuted(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
{
}
public static void RewriteFullTextQuery(DbCommand cmd)
{
string text = cmd.CommandText;
for (int i = 0; i < cmd.Parameters.Count; i++)
{
DbParameter parameter = cmd.Parameters[i];
if (parameter.DbType.In(DbType.String, DbType.AnsiString, DbType.StringFixedLength, DbType.AnsiStringFixedLength))
{
if (parameter.Value == DBNull.Value)
continue;
var value = (string)parameter.Value;
if (value.IndexOf(FullTextPrefix) >= 0)
{
parameter.Size = 4096;
parameter.DbType = DbType.AnsiStringFixedLength;
value = value.Replace(FullTextPrefix, ""); // remove prefix we added n linq query
value = value.Substring(1, value.Length - 2);
// remove %% escaping by linq translator from string.Contains to sql LIKE
parameter.Value = value;
cmd.CommandText = Regex.Replace(text,
string.Format(
#"\[(\w*)\].\[(\w*)\]\s*LIKE\s*#{0}\s?(?:ESCAPE N?'~')",
parameter.ParameterName),
string.Format(#"contains([$1].[$2], #{0})",
parameter.ParameterName));
if (text == cmd.CommandText)
throw new Exception("FTS was not replaced on: " + text);
text = cmd.CommandText;
}
}
}
}
}
static class LanguageExtensions
{
public static bool In<T>(this T source, params T[] list)
{
return (list as IList<T>).Contains(source);
}
}
For example, if you have class Note with FTS-indexed field NoteText:
public class Note
{
public int NoteId { get; set; }
public string NoteText { get; set; }
}
and EF map for it
public class NoteMap : EntityTypeConfiguration<Note>
{
public NoteMap()
{
// Primary Key
HasKey(t => t.NoteId);
}
}
and context for it:
public class MyContext : DbContext
{
static MyContext()
{
DbInterception.Add(new FtsInterceptor());
}
public MyContext(string nameOrConnectionString) : base(nameOrConnectionString)
{
}
public DbSet<Note> Notes { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new NoteMap());
}
}
you can have quite simple syntax to FTS query:
class Program
{
static void Main(string[] args)
{
var s = FtsInterceptor.Fts("john");
using (var db = new MyContext("CONNSTRING"))
{
var q = db.Notes.Where(n => n.NoteText.Contains(s));
var result = q.Take(10).ToList();
}
}
}
That will generate SQL like
exec sp_executesql N'SELECT TOP (10)
[Extent1].[NoteId] AS [NoteId],
[Extent1].[NoteText] AS [NoteText]
FROM [NS].[NOTES] AS [Extent1]
WHERE contains([Extent1].[NoteText], #p__linq__0)',N'#p__linq__0 char(4096)',#p__linq__0='(john)
Please notice that you should use local variable and cannot move FTS wrapper inside expression like
var q = db.Notes.Where(n => n.NoteText.Contains(FtsInterceptor.Fts("john")));
I have found that the easiest way to implement this is to setup and configure full-text-search in SQL Server and then use a stored procedure. Pass your arguments to SQL, allow the DB to do its job and return either a complex object or map the results to an entity. You don't necessarily have to have dynamic SQL, but it may be optimal. For example, if you need paging, you could pass in PageNumber and PageSize on every request without the need for dynamic SQL. However, if the number of arguments fluctuates per query, it will be the optimal solution.
As the other guys mentioned, I would say start using Lucene.NET
Lucene has a pretty high learning curve, but I found an wrapper for it called "SimpleLucene", that can be found on CodePlex
Let me quote a couple of codeblocks from the blog to show you how easy it is to use. I've just started to use it, but got the hang of it really fast.
First, get some entities from your repository, or in your case, use Entity Framework
public class Repository
{
public IList<Product> Products {
get {
return new List<Product> {
new Product { Id = 1, Name = "Football" },
new Product { Id = 2, Name = "Coffee Cup"},
new Product { Id = 3, Name = "Nike Trainers"},
new Product { Id = 4, Name = "Apple iPod Nano"},
new Product { Id = 5, Name = "Asus eeePC"},
};
}
}
}
The next thing you want to do is create an index-definition
public class ProductIndexDefinition : IIndexDefinition<Product> {
public Document Convert(Product p) {
var document = new Document();
document.Add(new Field("id", p.Id.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED));
document.Add(new Field("name", p.Name, Field.Store.YES, Field.Index.ANALYZED));
return document;
}
public Term GetIndex(Product p) {
return new Term("id", p.Id.ToString());
}
}
and create an search index for it.
var writer = new DirectoryIndexWriter(
new DirectoryInfo(#"c:\index"), true);
var service = new IndexService();
service.IndexEntities(writer, Repository().Products, ProductIndexDefinition());
So, you now have an search-able index. The only remaining thing to do is.., searching! You can do pretty amazing things, but it can be as easy as this: (for greater examples see the blog or the documentation on codeplex)
var searcher = new DirectoryIndexSearcher(
new DirectoryInfo(#"c:\index"), true);
var query = new TermQuery(new Term("name", "Football"));
var searchService = new SearchService();
Func<Document, ProductSearchResult> converter = (doc) => {
return new ProductSearchResult {
Id = int.Parse(doc.GetValues("id")[0]),
Name = doc.GetValues("name")[0]
};
};
IList<Product> results = searchService.SearchIndex(searcher, query, converter);
The example here http://www.entityframework.info/Home/FullTextSearch is not complete solution. You will need to look into understand how the full text search works. Imagine you have a search field and the user types 2 words to hit search. The above code will throw an exception. You need to do pre-processing on the search phrase first to pass it to the query by using logical AND or OR.
for example your search phrase is "blah blah2" then you need to convert this into:
var searchTerm = #"\"blah\" AND/OR \"blah2\" ";
Complete solution would be:
value = Regex.Replace(value, #"\s+", " "); //replace multiplespaces
value = Regex.Replace(value, #"[^a-zA-Z0-9 -]", "").Trim();//remove non-alphanumeric characters and trim spaces
if (value.Any(Char.IsWhiteSpace))
{
value = PreProcessSearchKey(value);
}
public static string PreProcessSearchKey(string searchKey)
{
var splitedKeyWords = searchKey.Split(null); //split from whitespaces
// string[] addDoubleQuotes = new string[splitedKeyWords.Length];
for (int j = 0; j < splitedKeyWords.Length; j++)
{
splitedKeyWords[j] = $"\"{splitedKeyWords[j]}\"";
}
return string.Join(" AND ", splitedKeyWords);
}
this methods uses AND logic operator. You might pass that as an argument and use the method for both AND or OR operators.
You must escape none-alphanumeric characters otherwise it would throw exception when a user enters alpha numeric characters and you have no server site model level validation in place.
I recently had a similar requirement and ended up writing an IQueryable extension specifically for Microsoft full text index access, its available here IQueryableFreeTextExtensions

Cast ActionScript Object to Model

Is there any "automatic way" to casts an "Object" to a personalized Model Data Type in ActionScript 3?
Example:
package Example{
public class ExampleModel{
private _id:int;
private _randomAttribute:String;
public function ExampleModel(){
_id = 0;
_randomAttribute = "";
}
public function get id():int{
return _id;
}
public function set id(value:int):void{
_id = value;
}
public function get randomAttribute():String{
return _randomAttribute;
}
public function set randomAttribute(value:String):void{
_randomAttribute = value;
}
}
}
Then, in some part of my code, lets assume that I have something like this:
var _obj:Object = new Object();
_obj.id = 1;
obj.randomAttribute = "Hello World";
What I want would be something like:
var _exampleModel:ExampleModel = obj as ExampleModel;
But when I do this, the result on _exampleModel is null.
Any ideas?
Thanks.
EDIT:
According to Manish's answer, all I changed was the type of p var, which allows me to go through every kind of attribute:
public function fromObject(obj:Object):void{
//p:* includes every type of attributes.
for (var p:* in obj)
if (this.hasOwnProperty(p))
// Set private var directly.
this["_" + p] = obj[p];
}
Thanks Manish and rcdmk.
Manish's answer was enough for me and according to rcdmk's comment, the p:String isn't about the Type of data that the loop will go through, it is actually the name of the property, which makes sense because every name is a String.
The only way to automatically "cast" it is the following:
var model:Model = new Model();
var obj:Object = { id: "98123", name: "John Doe" };
for (var p:String in obj) {
if (model.hasOwnProperty(p))
model[p] = obj[p];
}
(Note: Model.id and Model.name are both type String in my example.)
A more proper way to do it, of course, is to pass the plain object to the Model object and let the Model object absorb it.
var model:Model = new Model(obj);
Or:
var model:Model = new Model();
model.fromObject(obj);
Where in the Model code you have:
public function Model(obj:Object = null)
{
if (obj != null)
fromObject(obj);
}
public function fromObject(obj:Object):void
{
for (var p:String in obj)
if (this.hasOwnProperty(p))
// Set private var directly.
this["_" + p] = obj[p];
}
This code can be in your abstract base Model class, and all your specific Model subclasses (e.g. ProductModel, CustomerModel, etc.) can use it automatically.
e.g.
public class ProductModel extends Model
{
public function ProductModel(obj:Object = null)
{
super(obj);
}
}

Help with linq2sql generic lambda expression

In my Database almost every table has its own translations table. I.e. Sports has SportsTranslations table with columns: SportId, LanguageId, Name. At the moment I'm taking translations like:
int[] defaultLanguages = { 1, 3 };
var query = from s in dc.Sports
select new
{
sportName = s.SportsTranslations.Where(st => defaultLanguages.Contains(st.LanguageID)).First()
};
I wonder is it possible to implement some kind of generic method, so I could refactor code like here:
var query = from s in dc.Sports
select new
{
sportName = s.SportsTranslations.Translate()
};
Solved. Here is the static method I written:
public static class Extras
{
public static T Translate<T>(this IEnumerable<T> table) where T : class
{
try
{
return table.Where(
t => defaultLanguages.Contains(
(int)t.GetType().GetProperty("LanguageID").GetValue(t, null)
)
).First();
}
catch (Exception)
{
throw new ApplicationException(string.Format("No translation found in table {0}", typeof(T).Name));
}
}
}

Resources