Entity framework find similar string - c#

Is there a way how to find similar string in database via EF?
I would like to show users already existing questionts when he tries to add a new one (Implementation of exactly same feature as here on stack overflow "Questions that may already have your answer").
And order them by relevancy

well you can execute any arbitary sql and get entity framework object back.
using (var context = new myContext())
{
var myObject= context.myObject.SqlQuery("SELECT * FROM dbo.myObject where 'super duper where statement'").ToList();
}
And you can use full text search and all sorts of strange mechanisms in your sql statements.
look at this answer for further info

I believe stackoverflow is currently using the popular elasticsearch engine to index the entries and provide this functionality and it would be pretty cumbersome to try and implement this using only EF (if at all possible). However you still can use the normal string methods (StartsWith, Contains, etc) for providing some somewhat complex search functionality other than the simple matching of strings. For example:
var searchResult = Context.Products.All(x => x.Name.Contains("searchTerm"));

Related

Add sort on reflected navigation property

I'm using EF 6.0 .NET-Framework and MS SQL Sever and I have the follow situation: I have a dynamic data selection on a Navigation property from a given entity. This works so far OK. But: I like to add some sortings. But I cannot figure out how to make EF understand, that the sort shall be sent to the database instead sorting on client side afterwards.
The problem seems, that the data is requested from database when I retrieve the navigation property's value and not when I complete the command chain with the sort.
My code is like (simplyfied):
var dynamicRelatedEntityType = typeof(RelatedEntity);
using (var dbContext = new DBContext())
{
var orderByFunction = buildOrderByFunction(dynamicRelatedEntityType ); // this just builds a function for the order by ...
var masterEntity = dbContext.MasterEntity.first(x=> x.Whatever = true);
var navigationProperty = masterEntity.GetType().GetProperty(dynamicRelatedEntityType.Name);
var result = navigationProperty.GetValue(masterEntity).OrderBy(orderByFunction).ToList();
// result is OK, but sort wasn't sent to data base ... it was done by my program which is quite time expensive and silly too ...
}
So, how I can change this behaviour, any ideas?
Thank you in advance!
EDIT
The solution provided for this question solves to do dynamic predicates, but you cannot apply them if you still use navigationProperty.GetValue(masterEntity). In that case the EF will fire SQL immediatley without any order or where clause ...
Your database server is able to process TSQL statements only. Entity Framework (particularly the SQL Server pluging for Entity Framework) is capable of translating a small subset of C# expressions in a valid TSQL (in your case for an order by statement).
When your expression is too complex (for example invokes methods, alters the state) to be translanted into TSQL, Entity Framework will resort to an in memory operation.
If your are using .NET Core, you can use the following snipped while registering the content to spot all the "unsupported" statements that are executed in memory.
var builder = new DbContextOptionsBuilder<MyContext>();
var connectionString = configuration.GetConnectionString("DefaultConnection");
builder.UseSqlServer(connectionString);
// the following line is the one that prevents client side evaluation
builder.ConfigureWarnings(x => x.Throw(RelationalEventId.QueryClientEvaluationWarning));
Givem that, which is important to understand when a custom expression is involved, LINQ requires a static expression to infer the ordering. However, you can generate a dynamic expression as suggested by LINQ Dynamic Expression Generation. Although I never tried the described approach, it seems to me a viable way to achieve what you ask.

How can I use Entity Framework to load the results of a stored procedure?

I have a challenge. We have a database that was originally designed to be used with VB6 and most of the functionality sits in stored procedures. I cannot make changes to the stored procedures as the old application will still need to work for a while and I do not have my own copy of the database that I can modify even briefly.
So is it possible to execute a stored procedure from EF and have it do it's best to write the results into an array/collection of POCOs?
I've tried the database first approach and import but EF says the stored procedure does not return any columns and so cannot create a complex type. I've found there are ways to change the stored procedure to allow this to work but I cannot alter the database I'm using.
Another challenge is that the names of the columns in the results are things like 'Date last changed' in other words with spaces. How will EF try to map these? Would it become DataLastChanged or possibly Data_last_changed? Is there a way to mark my POCO with attributes to say how they are mapped?
What I was hoping for is something like
var resuls = efContext.ExecuteStoredProcedure<MyPOCOType>("spName",param1, param2, ...);
And have EF do it's best to match the results to the type. Does such a thing exist? Incidentally we are using EF4 but I believe 5 is available to us.
I think I've cracked part of the problem for myself. The following snippet does what I need.
using (DbContext context = new DbContext("DBConnectionStringNameFromAppConfig"))
{
SqlParameter[] parameters =
{
new SqlParameter("#OwnerID", DBNull.Value),
new SqlParameter("#ExternalColorID", colorOwner.ExternalColorID),
new SqlParameter("#ProductionSiteID", DBNull.Value),
new SqlParameter("#PanelstatusNr", DBNull.Value),
new SqlParameter("#DateLastChecked", DBNull.Value),
new SqlParameter("#rowcount", DBNull.Value),
};
var colors = context.Database.SqlQuery<Models.ColorSelectEvaluation>("[dbo].[sp_Color_Select_Evaluation] #OwnerID, #ExternalColorID, #ProductionSiteID, #PanelstatusNr, #DateLastChecked, #rowcount", parameters).ToList();
}
The confusing this is still the naming of the columns. They mostly seem to work but EF is not mapping the resulting column 'Needs evaluation' to the property NeedsEvaluation on my object.
Regarding the column names not matching. Another Q&A on stackoverflow deals with this nicely.
Why is my DbModelBuilder configuration ignored when mapping Entity from DbSet<T>.SqlQuery?
To summarise, MS think it would be great but they do not support mapping of names in this way. The only solution is to change the stored procedure and that is no option for me as it would break the legacy applications still using it.

sorting on related field in llblgen 2.6

I inherited an application that uses llblgen 2.6. I have a PersonAppointmentType entity that has a AppointmentType property (n:1 relation). Now I want to sort a collection of PersonAppointmentTypes on the name of the AppointmentType. I tried this so far in the Page_Load:
if (!Page.IsPostBack)
{
var p = new PrefetchPath(EntityType.PersonAppointmentTypeEntity);
p.Add(PersonAppointmentTypeEntity.PrefetchPathAppointmentType);
dsItems.PrefetchPathToUse = p;
// dsItems.SorterToUse = new SortExpression(new SortClause(PersonAppointmentTypeFields.StartDate, SortOperator.Ascending)); // This works
dsItems.SorterToUse = new SortExpression(new SortClause(AppointmentTypeFields.Name, SortOperator.Ascending));
}
I'm probably just not getting it.
EDIT:
Phil put me on the right track, this works:
if (!Page.IsPostBack)
{
dsItems.RelationsToUse = new RelationCollection(PersonAppointmentTypeEntity.Relations.AppointmentTypeEntityUsingAppointmentTypeId);
dsItems.SorterToUse = new SortExpression(new SortClause(AppointmentTypeFields.Name, SortOperator.Ascending));
}
You'll need to share more code if you want an exact solution. You didn't post the code where you actually fetch the entity (or collection). This may not seem relevant but it (probably) is, as I'm guessing you are making a common mistake that people make with prefetch paths when they are first trying to sort or filter on a related entity.
You have a prefetch path from PersonAppointmentType (PAT) to AppointType (AT). This basically tells the framework to fetch PATs as one query, then after that query completes, to fetch ATs based on the results of the PAT query. LLBLGen takes care of all of this for you, and wires the objects together once the queries have completed.
What you are trying to do is sort the first query by the entity you are fetching in the second query. If you think in SQL terms, you need a join from PAT=>AT in the first query. To achieve this, you need to add a relation (join) via a RelationPredicateBucket and pass that as part of your fetch call.
It may seem counter-intuitive at first, but relations and prefetch paths are completely unrelated (although you can use them together). You may not even need the prefetch path at all; It may be that you ONLY need the relation and sort clause added to your fetch code (depending on whether you actually want the AT Entity in your graph, vs. the ability to sort by its fields).
There is a very good explanation of Prefetch Paths and how they were here:
http://www.llblgening.com/archive/2009/10/prefetchpaths-in-depth/
Post the remainder of your fetch code and I may be able to give you a more exact answer.

Can you apply OOP to Linq Projections?

Using
Visual Studio 2010
.Net Framework 4
C#
Linq to Entities
Issue
I would like to be able to apply Object Oriented Principles like DRY and SOLID to some Linq Projections. With compiled queries or passed parameters I can apply these to the rest of Linq successfully so far, just not in the projections.
Please let me know if this isn't possible, and I must choose one of my alternate solutions (described below), if it is possible then how, or if I am missing something and there is another alternative implementation that will satisfy the goal.
Details
At a high level I would like to be able to dynamically control the type used in a Linq Projection, either with a standard Linq Query or a CompiledQuery. I am using Linq to Entities in my examples and actual code, however the issue should be applicable to the core Linq.
Below are simplistic examples that are not dynamic and do not solve the issue. They are fixed to always use the FooUser for each type. What I would like to be able to do is dynamically control the type of user created in the projection all of which would be based on a common IUser interface. This would be or could be similar to how I can control what type the query filters on.
Alternate Solutions
I am trying to conform to DRY, SOLID, and also trying to avoid using an enum to deal which is a typical code smell. However in all my attempts and research I seem to have to fall to one of the following solutions.
Implement a query for each type
which are all the same except for
the type they filter on and the type
used int he projection. While this
violates DRY and OCP, I can
encapsulate this within a single
class and keep them close together
as complied queries. This will
require the class to change if I add
a new type or if how you query for
the data changes.
Implement a enum that has the types, and use a more generalized User class that has its type as a property. However this will cause me to have to use the enum in several locations and introduce long case statements to handle them, which I would like to avoid.
I would love not to have to choose between different evils, and have an implementation that can conform to all SOLID principles and DRY. However if I must I think I will end up with the first or a version of it.
Examples
Standard Simple Linq Query
using (MyEntities context = new MyEntities())
{
var results = from u in context.Users
where u.UserType == type
select new FooUser
{
Id = u.UserID,
Name = u.UserName,
Location = u.UserLocation
};
}
Compiled Version of the Above Query
private static readonly Func<MyEntities, int, IQueryable<FooUser>> query = CompiledQuery.Compile<MyEntities, int, IQueryable<FooUser>>(
(context, type) => from u in context.Users
where u.UserType == type
select new FooUser
{
Id = u.UserID,
Name = u.UserName,
Location = u.UserLocation
});-
I found a way to do this with a standard method call. I haven't figured out how to do it with a compiled query, it doesn't look likely.
I was not aware of the Constructor Constraint I on the where statement for a generic. This can suit my needs. I would love to do this with a compiled query, but can live happy with this solution.
public IQueryable<IUser> FooMethod<T>(int type) where T : IUser, new()
{
using (MyEntities context = new MyEntities())
{
var results = from u in context.users
where u.usertype == type
select new T
{
id = u.UserId,
name = u.UserName,
location = u.Userlocation
};
return results;
}
}
I chose to post an answer instead of deleting the question for two reasons, one in case others are looking for something similar it could be helpful. Then of course I could be way off base and its is always fun to have people shoot holes in things and see what better stuff we can come up with.

Why won't entity framework allow me to do a .FindBy....()

I create a EDM using my database and saw that while it was able to make relations like
Customers.First().Orders
there is nothing like
Customer.First().Orders.FindOrderByOrderID()
Customer.First().Orders.FindOrderByOrderName()
etc.
Maybe I was expecting it to be like that and that's how it doesnt work
and I will probably just have to LINQ to entities and create mangers that handle business logic in them.
or does LINQ to SQL do this?
You can use LINQ with the Orders property, like this:
var order = Customer.First().Orders.FirstOrDefault(o => o.OrderId == someId);
This will return null if there was no matching Order.
With LINQ to Entities you can do this. Such as the example SLaks posted above.
If you're feeling adventurous, it is possible to write a function to do this. Since Entity Framework knows which column is the primary key it is possible to write a function like GetEntityByPrimaryKey.
CodeProject has an article regarding the repository pattern and if you search for "SelectByKey" you'll see their implementation of that. I use something similar and find it very helpful.
The idea is that you can use LINQ to write more flexible queries. Note, however, that you could probably so something like FindOrderByOrderName in .NET 4.0 by creating your own dynamic type (not trivial), that responded to calls following this pattern by building a LINQ query automatically. You'd lose intellisense, of course, and I doubt it would be worth it, but it could be done.

Categories

Resources