LINQ to Entities StringConvert(double)' cannot be translated to convert int to string - entity-framework-4

Problem
Need to convert int to string using EF4 + SQL CE4. The recommended option of using SqlFunctions.StringConvert(double) still gives me errors.
Option 1 (original). This gives me error:
public static IEnumerable<SelectListItem> xxGetCustomerList()
{
using (DatabaseEntities db = new DatabaseEntities())
{
var list = from l in db.Customers
orderby l.CompanyName
select new SelectListItem { Value = l.CustomerID.ToString(), Text = l.CompanyName };
return list.ToList();
}
}
Option 2 (most suggested). Then as many posts suggests, I used the SqlFunctions.StringConvert() function from the library System.Data.Objects.SqlClient:
public static IEnumerable<SelectListItem> GetCustomerList()
{
using (DatabaseEntities db = new DatabaseEntities())
{
var list = from l in db.Customers
orderby l.CompanyName
select new SelectListItem { Value = SqlFunctions.StringConvert((double)l.CustomerID), Text = l.CompanyName };
return list.ToList();
}
}
Which now shows below error:
The specified method 'System.String StringConvert(System.Nullable`1[System.Double])' on the type 'System.Data.Objects.SqlClient.SqlFunctions' cannot be translated into a LINQ to Entities store expression.
Option 3 (for very specific case). Then anoter post shows a smart solution using Dictionary, which finally works:
public static IEnumerable<SelectListItem> xGetCustomerList()
{
using (DatabaseEntities db = new DatabaseEntities())
{
var customers = db.Customers.ToDictionary(k => k.CustomerID, k => k.CompanyName);
var list = from l in customers
orderby l.Value
select new SelectListItem { Value = l.Key.ToString(), Text = l.Value };
return list.ToList();
}
}
But only work for simple pair values (key, value). Can someone help me with another solution or what I'm doing wrong with option 2?
And I hope Microsoft will soon make EF right before pushing us to move from L2S which is already stable and much more mature. I actually using EF4 just because want to use SQL CE, otherwise I stay with L2S.

EF is database independent at upper layers but the part dealing with conversion of linq query to SQL is always database dependent and SqlFunctions are dependent on SQL Server Provider but you are using SQL Server CE provider which is not able to translate functions from SqlFunctions class.
Btw. third option is also not a solution because it will select whole customer table to memory and use linq-to-objects after that. You should use this:
public static IEnumerable<SelectListItem> xxGetCustomerList()
{
using (DatabaseEntities db = new DatabaseEntities())
{
// Linq to entities query
var query = from l in db.Customers
orderby l.CompanyName
select new { l.CustomerID, l.CompanyName };
// Result of linq to entities transformed by linq to objects
return query.AsEnumerable()
.Select(x => new SelectListItem
{
Value = x.CustomerID.ToString(),
Test = x.CompanyName
}).ToList();
}
}

Here is a simplified version I'm using now (specific for SQL CE):
public static IEnumerable<SelectListItem> GetBlogCategoryList()
{
using (SiteDataContext db = new SiteDataContext())
{
var list = from l in db.BlogCategories.AsEnumerable()
orderby l.CategoryName
select new SelectListItem { Value = l.CategoryID.ToString(), Text = l.CategoryName };
return list.ToList();
}
}
Note the db.BlogCategories.AsEnumerable() part

Related

How to use COLLATE Latin1_General_bin in Entity framework?

I have to use COLLATE in entity framework query. How to write SQL query equivalent in Entity Framework as show below code?
SQL query:
select * from AspNetUsers order by Email COLLATE Latin1_General_bin
Entity Framework:
using (var db = new testEntities())
{
var appUsers = await db.Users.OrderBy(x => x.Email).ToListAsync();
}
It's possible to use Entity Framework's interception hooks.
The first step it to define an interface:
interface ISortInterceptable
{
IEnumerable<string> AdaptableSortFieldNames { get; set; }
}
Then make your context implement it:
class TestEntities : DbContext, ISortInterceptable
{
...
public IEnumerable<string> AdaptableSortFieldNames { get; set; }
...
}
Next, create a command interceptor:
class SortCommandInterceptor : DbCommandInterceptor
{
public override void ReaderExecuting(DbCommand command,
DbCommandInterceptionContext<DbDataReader> interceptionContext)
{
if (interceptionContext.DbContexts.First() is ISortInterceptable interceptable
&& interceptable.AdaptableSortFieldNames != null)
{
var query = command.CommandText;
foreach (var fieldName in interceptable.AdaptableSortFieldNames)
{
var pattern = $#"(.*\s*ORDER BY\s*.*\.)(\[{fieldName}\])(.*)";
query = Regex.Replace(query, pattern, "$1$2 COLLATE Latin1_General_bin $3");
}
command.CommandText = query;
}
base.ReaderExecuting(command, interceptionContext);
}
}
This is where all the magic happens.
The interceptor first checks if it has to do with a ISortInterceptable (maybe this check can be refined by getting all ISortInterceptables from interceptionContext.DbContexts).
The command text in the command to be executed is analyzed on any occurence of strings like ORDER BY [Alias].[fieldName] where fieldName is a variable. This search pattern is in keeping with the pattern EF always follows to generates queries.
The field name part of the ORDER BY clause, which is in the third group ($2) of the regex match, is extended by the collation phrase.
The replacement is repeated for all field names.
Finally, an example of how to use this interceptor:
DbInterception.Add(new SortCommandInterceptor());
using (var db = new TestEntities())
{
db.AdaptableSortFieldNames = new[] { "LastName", "Email" };
var users = db.AspNetUsers
.OrderBy(u => u.LastName)
.ThenBy(u => U.Email)
.ToList();
}
As always with string manipulation, one caveat: this works in a couple of my own tests, but I can't guarantee it to be rock solid. For one, the sorting fields should be text fields, of course.
One last note. EF core 3 also offers interception hooks that can be used in a similar way.

Best Way to Update only modified fields with Entity Framework

Currently I am doing like this:
For Example:
public update(Person model)
{
// Here model is model return from form on post
var oldobj = db.Person.where(x=>x.ID = model.ID).SingleOrDefault();
db.Entry(oldobj).CurrentValues.SetValues(model);
}
It works, but for example,
I have 50 columns in my table but I displayed only 25 fields in my form (I need to partially update my table, with remaining 25 column retain same old value)
I know it can be achieve by "mapping columns one by one" or by creating "hidden fields for those remaining 25 columns".
Just wondering is there any elegant way to do this with less effort and optimal performance?
This is a very good question. By default I have found that as long as change tracking is enabled (it is by default unless you turn it off), Entity Framework will do a good job of applying to the database only what you ask it to change.
So if you only change 1 field against the object and then call SaveChanges(), EF will only update that 1 field when you call SaveChanges().
The problem here is that when you map a view model into an entity object, all of the values get overwritten. Here is my way of handling this:
In this example, you have a single entity called Person:
Person
======
Id - int
FirstName - varchar
Surname - varchar
Dob - smalldatetime
Now let's say we want to create a view model which will only update Dob, and leave all other fields exactly how they are, here is how I do that.
First, create a view model:
public class PersonDobVm
{
public int Id { get; set; }
public DateTime Dob { get; set; }
public void MapToModel(Person p)
{
p.Dob = Dob;
}
}
Now write the code roughly as follows (you'll have to alter it to match your context name etc):
DataContext db = new DataContext();
Person p = db.People.FirstOrDefault();
// you would have this posted in, but we are creating it here just for illustration
var vm = new PersonDobVm
{
Id = p.Id, // the Id you want to update
Dob = new DateTime(2015, 1, 1) // the new DOB for that row
};
vm.MapToModel(p);
db.SaveChanges();
The MapToModel method could be even more complicated and do all kinds of additional checks before assigning the view model fields to the entity object.
Anyway, the result when SaveChanges is called is the following SQL:
exec sp_executesql N'UPDATE [dbo].[Person]
SET [Dob] = #0
WHERE ([Id] = #1)
',N'#0 datetime2(7),#1 int',#0='2015-01-01 00:00:00',#1=1
So you can clearly see, Entity Framework has not attempted to update any other fields - just the Dob field.
I know in your example you want to avoid coding each assignment by hand, but I think this is the best way. You tuck it all away in your VM so it does not litter your main code, and this way you can cater for specific needs (i.e. composite types in there, data validation, etc). The other option is to use an AutoMapper, but I do not think they are safe. If you use an AutoMapper and spelt "Dob" as "Doob" in your VM, it would not map "Doob" to "Dob", nor would it tell you about it! It would fail silently, the user would think everything was ok, but the change would not be saved.
Whereas if you spelt "Dob" as "Doob" in your VM, the compiler will alert you that the MapToModel() is referencing "Dob" but you only have a property in your VM called "Doob".
I hope this helps you.
I swear by EntityFramework.Extended. Nuget Link
It lets you write:
db.Person
.Where(x => x.ID == model.ID)
.Update(p => new Person()
{
Name = newName,
EditCount = p.EditCount+1
});
Which is very clearly translated into SQL.
Please try this way
public update(Person model)
{
// Here model is model return from form on post
var oldobj = db.Person.where(x=>x.ID = model.ID).SingleOrDefault();
// Newly Inserted Code
var UpdatedObj = (Person) Entity.CheckUpdateObject(oldobj, model);
db.Entry(oldobj).CurrentValues.SetValues(UpdatedObj);
}
public static object CheckUpdateObject(object originalObj, object updateObj)
{
foreach (var property in updateObj.GetType().GetProperties())
{
if (property.GetValue(updateObj, null) == null)
{
property.SetValue(updateObj,originalObj.GetType().GetProperty(property.Name)
.GetValue(originalObj, null));
}
}
return updateObj;
}
I have solved my Issue by using FormCollection to list out used element in form, and only change those columns in database.
I have provided my code sample below; Great if it can help someone else
// Here
// collection = FormCollection from Post
// model = View Model for Person
var result = db.Person.Where(x => x.ID == model.ID).SingleOrDefault();
if (result != null)
{
List<string> formcollist = new List<string>();
foreach (var key in collection.ToArray<string>())
{
// Here apply your filter code to remove system properties if any
formcollist.Add(key);
}
foreach (var prop in result.GetType().GetProperties())
{
if( formcollist.Contains(prop.Name))
{
prop.SetValue(result, model.GetType().GetProperty(prop.Name).GetValue(model, null));
}
}
db.SaveChanges();
}
I still didn't find a nice solution for my problem, so I created a work around. When loading the Entity, I directly make a copy of it and name it entityInit. When saving the Entity, I compare the both to see, what really was changed. All the unchanged Properties, I set to unchanged and fill them with the Database-Values. This was necessary for my Entities without Tracking:
// load entity without tracking
var entityWithoutTracking = Context.Person.AsNoTracking().FirstOrDefault(x => x.ID == _entity.ID);
var entityInit = CopyEntity(entityWithoutTracking);
// do business logic and change entity
entityWithoutTracking.surname = newValue;
// for saving, find entity in context
var entity = Context.Person.FirstOrDefault(x => x.ID == _entity.ID);
var entry = Context.Entry(entity);
entry.CurrentValues.SetValues(entityWithoutTracking);
entry.State = EntityState.Modified;
// get List of all changed properties (in my case these are all existing properties, including those which shouldn't have changed)
var changedPropertiesList = entry.CurrentValues.PropertyNames.Where(x => entry.Property(x).IsModified).ToList();
foreach (var checkProperty in changedPropertiesList)
{
try
{
var p1 = entityWithoutTracking.GetType().GetProperty(checkProperty).GetValue(entityWithoutTracking);
var p2 = entityInit.GetType().GetProperty(checkProperty).GetValue(entityInit);
if ((p1 == null && p2 == null) || p1.Equals(p2))
{
entry.Property(checkProperty).CurrentValue = entry.Property(checkProperty).OriginalValue; // restore DB-Value
entry.Property(checkProperty).IsModified = false; // throws Exception for Primary Keys
}
} catch(Exception) { }
}
Context.SaveChanges(); // only surname will be updated
This is way I did it, assuming the new object has more columns to update that the one we want to keep.
if (theClass.ClassId == 0)
{
theClass.CreatedOn = DateTime.Now;
context.theClasses.Add(theClass);
}
else {
var currentClass = context.theClasses.Where(c => c.ClassId == theClass.ClassId)
.Select(c => new TheClasses {
CreatedOn = c.CreatedOn
// Add here others fields you want to keep as the original record
}).FirstOrDefault();
theClass.CreatedOn = currentClass.CreatedOn;
// The new class will replace the current, all fields
context.theClasses.Add(theClass);
context.Entry(theClass).State = EntityState.Modified;
}
context.SaveChanges();
In EF you can do like this
var result = db.Person.Where(x => x.ID == model.ID).FirstOrDefault();
if(result != null){
result.Name = newName;
result.DOB = newDOB;
db.Person.Update(result);
}
Or you can use
using (var db= new MyDbContext())
{
var result= db.Person.Where(x => x.ID == model.ID).FirstOrDefault();
result.Name= newName;
result.DOB = newDOB;
db.Update(result);
db.SaveChanges();
}
For more detail please EntityFramework Core - Update Only One Field
No Worry guys
Just write raw sql query
db.Database.ExecuteSqlCommand("Update Person set Name='"+_entity.Name+"' where Id = " + _entity.ID + "");

How to call web API 2 in Eclipse

I have ASP.Net MVC 5 Web API project.
I cant use asp.net web API 2 web service in android
my web service is under mvc5, Then I have created mobile app in Eclipse Juno and i use Android sdk 21
below is my edited code
namespace AppServices.Models
{
public class AdvertisingRepository
{
private List<Advertising> Advertising = new List<Advertising>();
private int _nextId = 1;
public AdvertisingRepository()
{
}
public List<Advertising> GetAll()
{
Advertising.Clear();
SqlDataReader reader = null;
SqlConnection myConnection = new SqlConnection();
myConnection.ConnectionString = #"Server=.;Database=AppServices;User ID=sa;Password=123;";
SqlCommand sqlCmd = new SqlCommand();
sqlCmd.CommandType = CommandType.Text;
sqlCmd.CommandText = "SELECT * FROM tblAdvertising";
sqlCmd.Connection = myConnection;
myConnection.Open();
reader = sqlCmd.ExecuteReader();
Advertising emp = null;
while (reader.Read())
{
emp = new Advertising();
emp.Id = Convert.ToInt32(reader.GetValue(0));
emp.SearchString = reader.GetValue(1).ToString();
emp.OstanID = Convert.ToInt32(reader.GetValue(2));
emp.AdsGroupID = Convert.ToInt32(reader.GetValue(3));
Advertising.Add(emp);
}
myConnection.Close();
return Advertising;
}
public Advertising Get(int id)
{
Advertising.Clear();
SqlDataReader reader = null;
SqlConnection myConnection = new SqlConnection();
myConnection.ConnectionString = #"Server=.;Database=AppServices;User ID=sa;Password=123;";
SqlCommand sqlCmd = new SqlCommand();
sqlCmd.CommandType = CommandType.Text;
sqlCmd.CommandText = "SELECT * FROM tblAdvertising WHERE Id=" + id + "";
sqlCmd.Connection = myConnection;
myConnection.Open();
reader = sqlCmd.ExecuteReader();
Advertising emp = null;
while (reader.Read())
{
emp = new Advertising();
emp.Id = Convert.ToInt32(reader.GetValue(0));
emp.SearchString = reader.GetValue(1).ToString();
emp.OstanID = Convert.ToInt32(reader.GetValue(2));
emp.AdsGroupID = Convert.ToInt32(reader.GetValue(3));
Advertising.Add(emp);
}
myConnection.Close();
return Advertising.Find(p => p.Id == id);
}
public Advertising Add(Advertising item)
{
SqlConnection myConnection = new SqlConnection();
myConnection.ConnectionString = #"Server=.;Database=AppServices;User ID=sa;Password=123;";
SqlCommand sqlCmd = new SqlCommand();
sqlCmd.CommandType = CommandType.Text;
sqlCmd.CommandText = "INSERT INTO tblAdvertising (SearchString, OstanID, AdsGroupID) VALUES (#SearchString, #OstanID, #AdsGroupID)";
sqlCmd.Connection = myConnection;
sqlCmd.Parameters.AddWithValue("#SearchString", item.SearchString);
sqlCmd.Parameters.AddWithValue("#OstanID", item.OstanID);
sqlCmd.Parameters.AddWithValue("#AdsGroupID", item.AdsGroupID);
myConnection.Open();
int rowInserted = sqlCmd.ExecuteNonQuery();
// Get new record id
sqlCmd.CommandText = "SELECT TOP (1) Id FROM tblAdvertising ORDER BY Id DESC";
if (sqlCmd.ExecuteScalar() != DBNull.Value)
_nextId = (int)sqlCmd.ExecuteScalar();
////////////////////
myConnection.Close();
// old code
if (item == null)
{
throw new ArgumentNullException("item");
}
item.Id = _nextId;
Advertising.Add(item);
return item;
}
public void Remove(int id)
{
Advertising.RemoveAll(p => p.Id == id);
}
public bool Update(Advertising item)
{
if (item == null)
{
throw new ArgumentNullException("item");
}
int index = Advertising.FindIndex(p => p.Id == item.Id);
if (index == -1)
{
return false;
}
Advertising.RemoveAt(index);
Advertising.Add(item);
return true;
}
}
}
I have ASP.Net MVC 5 Web API project. I cant use asp.net web API 2 web service in android my web service is under mvc5, Then I have created mobile app in Eclipse Juno and i use Android sdk 21 below is my edited code
There are many issues.
It starts with what looks a little careless "SELECT * FROM tblAdvertising"
That is three sins against the rules of SQL.
First there is no table called tblAdvertising. There is one called dbo.tblAdvertising. So lacking the real name SQL assumes that you mean dbo, but that might be something else as well. This will dump your performance. Best always use fully qualified names.
The second issue is that you use * as items to select. I have been a long in SQL development and can tell from own experience how often tables are changed. The person doing so might not even be aware of your application so a simple add will cause your code to break. Always use fully qualified SQL column names as well.
The final issue with your SQL is that you use a command and yet poke in text strings, even those that are unprotected against SQL injection. What if someone adds this as string "'',0,0; truncate table tblAdvertising; --". You might be surprised how often, certainly in the past i could log in websites simply with some variation of "'' or 1=1 --". Best avoid unprotected strings that go to MSSQL or MySQL or any SQL for that matter. Also your SQLstring needs to be compiled taking a further performance hit. There is also no protection against wrong parameters or proper feedback if the result does not exist.
Besides you really do not want to select an entire table. There should be like a top 100 or you could implement some paging.
So the solution is that you use a proper stored procedure, check the parameter input and provide limited and properly formatted output.
Also your
INSERT INTO tblAdvertising (SearchString, OstanID, AdsGroupID) VALUES (#SearchString, #OstanID, #AdsGroupID)
can be much improved.
If you update or insert there is an output statement in SQL that is massive faster than querying the max number
create type dbo.IntTable as table(i int)
go
create proc dbo.AdvertisementInsert
#SearchString varchar
, #OstanID int
, #AdsGroupID int
, #NewID int = 0 output
as
set nocount on -- important to avoid second roundtrip over the network
declare #i as dbo.IntTable -- use predefined table variable
-- always check quality of input first
if #SearchString is null return 50001
-- also avoid rollback transaction since that is costly.
-- Better to ask first if this not already exist
if exists(select 42 from dbo.tblAdvertising where SearchString = #SearchString) return 50002
INSERT INTO tblAdvertising (SearchString, OstanID, AdsGroupID)
output inserted.Id into #i -- catch new id directly into table variable
VALUES (#SearchString, #OstanID, #AdsGroupID)
-- report the result
select #NewID = i from #i -- convert table variable to single int
go
So now your proc can be called just using the parameters and will tell you back either 0 .. in which case the result code will tell you why it failed, or some other number matching the new identity
Enjoy

DataTables editable cant figure out how to delete/update rows

I am trying to implement dataTables plugin in server-side mode to render a table on my webpage. I am coding ASP.NET with c# and MVC.
I want to edit (delete/update/add) data to the table and write any change to my database.
But in difference to the example of this tutorial: http://www.codeproject.com/Articles/165410/ASP-NET-MVC-Editable-DataTable-jQuery-DataTables-a data provided by my controller does not contain a single primary key, but a compound key:
projectId and
questionId
Here's my controller, which provides data from my database:
public ActionResult AjaxHandler(jQueryDataTableParamModel param)
{
var any = (from pq in _db.ProjectQuestions
join q in _db.Question
on pq.QuestionID equals q.QuestionID
join c in _db.Category
on q.CategoryID equals c.CategoryID
select new
{
projectID = pq.ProjectID,
questionID = q.QuestionID,
categoryName = c.CategoryName,
questionName = q.QuestionName,
questionDescription = q.QuestionDescription
});
int count = any.Count();
var result = new List<object[]>();
return Json(new
{
sEcho = param.sEcho,
iTotalRecords = count,
iTotalDisplayRecords = count,
aaData = any
},
JsonRequestBehavior.AllowGet);
}
So far the standard DeleteData/UpdateData and AddData methods dont even receive any value for id.
public string DeleteData(int id)
{
return "ok";
}
How can I use the CRUD-functionality of Editable if my data has to be identified by two parameters?
So far I couldn't find any solution to edit data. Many thanks in advance.
_tek
I would suggest you to use Grid view function.
Please follow this video:
http://www.youtube.com/watch?v=vZIOI136IKY

mvc LinqToSql add row "Select User" for a dropdown list

I'm new to Linq. I have searched and searched the web for a solution, and can't find anything. I have a Linq query and I want to insert a row ("Select User") to the top before I pass it to the drop down list. I've been trying to use the Union but to now avail (it keeps telling me that my object doesn't support the Union method). My code, prior to attempting to insert a row, is very simple.
public SelectList DropDown_Users()
{
var context = new VivarianDataContext();
var query = from t in context.AspnetUsers
select new { t.UserId, t.LastName };
list = new SelectList(query.AsEnumerable(), "UserId", "LastName");
return list;
}
Now I try to insert a row and I found this on the internet and it seems to say that his solution will work. But it is filled with errors. http://magicode.wordpress.com/2009/08/20/inserting-an-item-in-iqueryable-object-using-union-method-and-linq/
I tried to implement it using the following code, but it doesn't compile.
public SelectList DropDown_Users()
{
SelectList list;
//get the original data
var context = new SQL2005633131VivarianDataContext();
var query = from t in context.AspnetUsers
select new { t.UserId, t.LastName };
//create a dummy table with an empty row
var AllUsers = new List<AspnetUsers>();
var BlankUser = new AspnetUsers()
{UserId=System.Guid.Empty, LastName="Select One"};
AllUsers.Add(BlankUser);
//use Union to join the data - ERRORS HERE - doesn't support Union
var newTable = AllUsers.Union(query);
list = new SelectList(newTable.AsEnumerable(), "UserId", "LastName");
return list;
}
So tired I'm going blind. Any help?
You don't need to touch the query result. You can add that default option "Select User" in the dropdownlist.
Try this:
How can I add an item to a SelectList in ASP.net MVC

Resources