I need to create a "common" grid with parameters.
The problem is that in the Delete action I cannot refer to the table as a variable
I use edmx model.
public ActionResult PartialView_GridCommonDelete(System.Int64 data_autoinc)
{
var table = ViewBag.CurrentTable;
var key= ViewBag.Key;
if (data_autoinc != null)
{
try
{
//ERROR HERE
var item = **ent.table**.FirstOrDefault(it => it.product_autoinc == data_autoinc);
if (item != null)
ent.tabla.Remove(item);
ent.SaveChanges();
}
catch (Exception e)
{
ViewData["EditError"] = e.Message;
}
}
return PartialView("PartialView_GridCommon", ViewBag.CurrentSql);
}
How can I dynamically substitute the table name so as I can use it with many tables?
Thank you
What you are trying to do is not achievable by ORM i.e. defining Table at runtime.
What you can try is:
context.Database.ExecuteSqlCommand("TRUNCATE TABLE [TableName]");
You can explicitly pass table name and fire your sql query
Give it a try.
Thanks
Nipun
Related
I made my database with its stored procedures then attached it with my project Entity Framework database-first.
This function to insert a company info and return its id back and insert it to another table in relation with company table
public string InsertCompany(company company, out int index)
{
try
{
using (vendors_managerEntities db = new vendors_managerEntities())
{
db.companies.Add(company);
db.SaveChanges();
index = company.id_company;
return $"{company.name_company} Is Saved";
}
}
catch (Exception ex)
{
index = 0;
return ex.Message;
}
}
But when I tried to my stored procedure which has been created in database, I couldn't return any value the id always be 0
public string InsertCompany(company company, out int index)
{
try
{
using (vendors_managerEntities db = new vendors_managerEntities())
{
db.SP_insert_companies(company.name_company, company.website_company, company.adress_company, company.county_company, company.decription_company);
index = company.id_company;
return $"{company.name_company} Is Saved";
}
}
catch (Exception ex)
{
index = 0;
return ex.Message;
}
}
I read that I can make it in SQL but I'm looking for a solution in C#, so I opened the stored procedure definition in C# and found the following code and was thinking if can I change its return value because it's not return the id value
public virtual int SP_insert_companies(string name, string website, string address, string country, string description)
{
var nameParameter = name != null ?
new ObjectParameter("name", name) :
new ObjectParameter("name", typeof(string));
var websiteParameter = website != null ?
new ObjectParameter("website", website) :
new ObjectParameter("website", typeof(string));
var addressParameter = address != null ?
new ObjectParameter("address", address) :
new ObjectParameter("address", typeof(string));
var countryParameter = country != null ?
new ObjectParameter("country", country) :
new ObjectParameter("country", typeof(string));
var descriptionParameter = description != null ?
new ObjectParameter("description", description) :
new ObjectParameter("description", typeof(string));
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction("SP_insert_companies", nameParameter, websiteParameter, addressParameter, countryParameter, descriptionParameter);
}
Please tell me if there's a solution in C# or should I go back to old code without stored procedure in that case?
The issue is that you are using a stored procedure to insert the company entity which I suspect does not cause the object to be refreshed by the context:
db.SP_insert_companies(company.name_company, company.website_company, company.adress_company, company.county_company, company.decription_company);
You then try to get the id from the object which is 0 because it hasn't been refreshed:
index = company.id_company;
If you insist on using a stored procedure, what I would suggest is that you have the SP return the id of the company, then grab it from the call and use that as the value of index:
index = db.SP_insert_companies(company.name_company, company.website_company, company.adress_company, company.county_company, company.decription_company);
Once you modify the SP, make sure to update the definition in your code so it knows to make a function that returns a value.
If you prefer to have it in the object itself, then make sure to update it manually, although I don't recommend this as the object is not in true sync with the database:
index = db.SP_insert_companies(company.name_company, company.website_company, company.adress_company, company.county_company, company.decription_company);
company.id_company = index;
Based on what you're saying it's automatically going to the "Catch" and then the index is already set to 0. So chances are your code elsewhere, not listed is messing up. I suspect wherever your code for saving the company information isn't saving properly. Try manually inputting a company into the DB and then check it with your program. If it returns that it's "Saved" then you know your problem isn't within this method and is a result of your saving method.
QUESTION :
Is there a clever way to dynamically add parameters to an object and insert them in to a SQL DB?
preferably using Dapper
I'm writing a WPF app where (amongest other things) I'm collecting questionnaire data. I'm using Dapper to map c# objects to SQL statements.
My problem is that I don't want to hard code all of the column names as object properties since I have a lot of them!
So I wanted to use Dapper's DynamicParameters to dynamically generate objects that Dapper can insert into the database by using the Dapper.Contrib Insert method.
I made an abstract class like this:
public abstract class IDbRecord : DynamicParameters
{
[Key]
public string H4Id { get; set; }
}
and added parameters in another method using the DynamicParameters.Add method.
When my parameters have been added to my IDbRecord derived object I try to insert it.
This results is the Insert medthod trying to insert the public properties of DynamicParameters and not the content of the private parameters Dictonary. Which makes sense when looking at the Readme of Dapper.Contrib. I was just hoping that they had implemented Insert() to grab the parameters Dictonary when the object was derived from DynamicParameters.
I enden up iterating through my objects and building a SQL INSERT statement with a StringBuilder. Not very elegant. But it works
if (!hasData)
{
var parameterList = new StringBuilder(null);
var valuesList = new StringBuilder(null);
var insertSql = new StringBuilder(null);
parameterList.AppendFormat("Id, ");
valuesList.Append(Id + ", ");
foreach (var questionBase in answerList)
{
if (string.IsNullOrEmpty(questionBase.VariableName))
{
throw new ArgumentException("Question " + questionBase.QuestionNumber +
" does not have a VariableName");
}
if (!string.IsNullOrEmpty(questionBase.VariableName) && questionBase.Answer != null)
{
// insert keys (variable names)
parameterList.AppendFormat("{0}", questionBase.VariableName);
if (questionBase.QuestionNumber != answerList.Last().QuestionNumber)
{
parameterList.Append(", ");
}
// insert values
valuesList.AppendFormat("{0}", questionBase.Answer);
if (questionBase.VariableName != answerList.Last().VariableName)
valuesList.Append(", ");
}
}
try
{
insertSql.AppendFormat("INSERT INTO {0} ({1}) VALUES ({2})", tableName, parameterList, valuesList);
Connect(ConnectionHelper.DevConnString,
c => c.Execute(insertSql.ToString()));
return true;
}
catch (Exception e)
{
return false;
}
}
I have a DB with no constraints (given, not changeable). My model look like
public MyModel
{
public long Id { get; set; }
// Even if database column 'Value' could be NULL,
// the model - from business view - could not.
public long Value { get; set; }
}
My data I'd like to read is
Id Value
1 1
2 2
3 NULL
4 4
When I read with with DBContext.MyModel.ToList() it fails, of course. Is there any possibility to catch the error on 3rd row and return the 3 valid ones?
I don't dependent on EF but I like an automatic mapping between DB an Code.
Update:
It seems I wasn't specific enough. I need the 3 rows AS WELL AS a notification for the error.
Additional I've created a simple case for demo. In real life I have around 800 tables with up to 250 columns. I can't catch anything by model modification like dates out of range, missing relationships and other stuff.
What I really need is a try..catch for every row or an event on row reading failure, something like this.
Ok, solved. Not very elegant, but functional.
var query = _DBContext
.Database
.SqlQuery<MyModel>("SELECT * FROM MyModel");
var result = new List<MyModel>();
var enumerator = query.GetEnumerator();
while (true)
{
try
{
var success = enumerator.MoveNext();
if (!success)
break;
var model = enumerator.Current;
result.Add(model);
}
catch (Exception ex)
{
}
}
return result;
You need to use nullable type
public MyModel
{
public long Id { get; set; }
// Even if database column 'Value' could be NULL,
// the model - from business view - could not.
public long? Value { get; set; }
}
And also, in your select query, you should exlude Value = null
var myModel = models.Where(x => x.Value != null);
Hope it helps.
I'm not entirely sure I understand what you're trying to do, but if you want to get a reflection of what's in the table, then why not make your model match the query? If Value can be NULL, then make Value nullable (i.e. define it as long?).
That way, you can simply do:
var records = DbContext.MyModel.ToList();
If you then want to filter out the NULLs, you can do:
records.Where(r => r.Value.HasValue)
And if you want the ones with NULLs you can do:
records.Where(r => !r.Value.HasValue)
Or if you want to know whether any row had a NULL you could do:
records.Any(r => !r.Value.HasValue)
Use the following code:
var list = from m in DBContext.MyModel
where (m != null)
select m;
And then just convert var list to a List of your choosing.
Edit 1
var myModel = models.Where(x => x.Value != null).ToList();
As kienct89 suggested might also work.
Edit 2
There are multiple options for "catching" the error
If you want to throw an exception just use this:
if(myList.Count() < DBContext.MyModel.Count()){
Exception myException = new Exception("Not all items ware correctly loaded");
throw myException;
}
OR create a seperate array with the faulty ones:
var faultyList = from m in DBContext.MyModel
where (m == null)
select m;
Or:
var faultyList= models.Where(x => x.Value == null).ToList();
I am writing a crawler that should go to a website, extract some data from there and then store it into a db, the thing is the crawler should also update the data that has already been found in a prior run.
The ParseDataPage returns the information parsed from the site in a EF POCO, one of its properties is a unique identifier (which also is the primary key in the db table), how can I tell EF to insert/add the object?
class Program
{
static void Main()
{
var context = (adCreatorEntities) DbContextFactory.GetInstance().GetDbContext<adCreatorEntities>();
var crawler = new DataCrawler();
crawler.Login();
var propertyIds = crawler.GetPropertyIds();
foreach (var id in propertyIds)
{
var poco = crawler.ParseDataPage(id);
context.Properties.Add(poco); //<-- How can I tell EF to update if the record exists or to insert it otherwise??
context.SaveChanges();
}
context.SaveChanges();
if (crawler.LoggedIn)
crawler.Logout();
}
}
You can set the entity state to Modified or Add the entity to the DbSet based on the key's value.
if(entity.propertyId <= 0)
{
context.Properties.Add(poco);
}
else
{
context.Entry(poco).State = EntityState.Modified;
}
This is code for EF5, EF4 is slightly different for setting object state
context.ObjectStateManager.ChangeObjectState(poco, EntityState.Modified);
you can check whether record exists or not using following code,
var entity= dataContext.Properties.Find(b => b.UniqueId == poco.UniqueId);
if (entity== null)
{
dataContext.Properties.Add(poco);
}
else
{
dataContext.Entry(entity).State = EntityState.Modified;
}
dataContext.SaveChanges();
Im want to delete rows from a table that in my data base.
i have the member
private static WeightScaleEntities Weight = new Weight();
this member contains my database. in the data base i have table: User_Activity.
I want to delete rows from user activity by given i_UserActivityId, as follow:
//Get the rows for delete
var deleteUserActivities = from details in Weight.User_Activity
where details.Id == i_UserActivityId
select details;
Now i want to delete this rows, so i tried to do:
foreach (var item in deleteUserActivities)
{
m_WeightScaleEntities.User_Activity.*
}
and i dont get the method DeleteOnSubmit!
Why?
there is another option???
User_Activity.*: is that a typo?
What I think you want is:
foreach (var item in deleteUserActivities)
{
Weight.DeleteObject(item);
}
And then SaveChanges() on the object context.
BTW, a static object context is not a good idea. You should carefully control the life cycle of object contexts.
There is more than one way to execute deletion in Entity Framework,
You must take into account what are the values that you want to delete? one Row or more.
when you need to delete on Row from table we can use these ways:
// first way
using (WeightScaleEntities db = new WeightScaleEntities())
{
var deleteUserActivities = from details in db.User_Activity
where details.Id == i_UserActivityId
select details;
if (deleteUserActivities.Count() > 0)
{
db.deleteUserActivities.Remove(deleteUserActivities.First());
db.SaveChanges();
}
}
this line deleteUserActivities.Count()>0 to check if you have result in the Query or not.
and this deleteUserActivities.First() if the query return set of rows delete the first. "to make the process more secure if you don't know about the data in the table"
// second way
using (WeightScaleEntities db = new WeightScaleEntities())
{
var deleteUserActivities = (from details in db.User_Activity
where details.Id == i_UserActivityId
select details).SingleOrDefault();
if (deleteUserActivities != null)
{
db.User_Activity.Remove(deleteUserActivities);
// or use this line
//db.Entry(deleteUserActivities).State = System.Data.Entity.EntityState.Deleted;
db.SaveChanges();
}
}
You can also use Single or SingleOrDefault to get a single object. Single or SingleOrDefault will throw an exception, if the result contains more than one element. Use Single or SingleOrDefault where you are sure that the result would contain only one element. If the result has multiple elements then there must be some problem.
Also, if you need to remove one or multi rows use this way:
using (WeightScaleEntities db = new WeightScaleEntities())
{
var deleteUserActivities = (from details in db.User_Activity
where details.Id == i_UserActivityId
select details).ToList<User_Activity>(); //<User_Activity> her name of your DbSet
foreach(deleteObject in deleteUserActivities)
{
db.Entry(deleteObject).State = System.Data.Entity.EntityState.Deleted;
}
db.SaveChanges();
}
Best Regards
and sorry about English language.
using(WeightScaleEntities db=new WeightScaleEntities())
{
var deleteUserActivities = from details in db.User_Activity
where details.Id == i_UserActivityId
select details;
if (deleteUserActivities.Count()>0)
{
db.deleteUserActivities.Remove(deleteUserActivities.First());
db.SaveChanges();
}
}