If condition with Entity Framework - c#

In my asp.net application I have two pages like new students and edit students. On the new student page I am passing general details like first name, last name, mobile number, email and register number.
Here RegNo should be unique. I am using Entity Framework for database connection. I'm checking with the condition to avoid the same RegNo being entered, like:
DataObject.Entities dataEntities = new DataObject.Entities();
if (!dataEntities.Students.Any(s => s.RegNo == RegNo))
{
// my code here.
}
The same way for edit option, when try to change the RegNo. If it is allotted to some other student, it should not go into the update code.
I know if I use the same condition here, it will fail, because the RegNo is there in the database for this student (the one am trying to update), so if the RegNo is allotted for this particular student and not for other students it should be accepted, otherwise should go to else part.
I don't know how to check this using Entity Framework. Can anyone help me,please?
I've a column StudentId, it's an autoincrement column
I tried like
if (!dataEntities.Students.Any(s => s.RegNo == RegNo && s.StudentId != StudentId))
{
}
still it's not working.....

if(!dataEntities.Students.Any(s=>s.RegNo == RegNo && s != studentBeingUpdated))
Replace studentBeingUpdated with a variable containing a reference to the student that you are currently updating.

you can set in database level.. ie if you set auto increment then you dont need to edit/ reassign id to someone else and there is no need for separate management for this.
Please tell me if i understood mistakenly. :)

I just declared an object for the student table and tried like,
DataObject.Student student = dataEntities.Students.First(s => s.StudentId ==
StudentId);
if (!dataEntities.Students.Any(s => s.RegNo == RegNo &&
s.StudentId != student.StudentId))
{
}
else
{
throw new exception("RegNo already exists!");
}
and its working for me

Related

How to make sql query more dynamic in ASP.NET

I have a webpage and a gridview connected to a database table. My update queries of the columns are as followed:
if (oldName != NAME && oldCreated == DATE)
{
GeneralDbExecuterService.executeSqlNonQuery(string.Format("UPDATE EXCEPTIONAL_USE_POLICY_PARAM SET NAME = '{0}' WHERE ID = '{1}' ", NAME, ID));
}
// if date was changed alone
if (oldCreated != DATE && oldName == NAME)
{
GeneralDbExecuterService.executeSqlNonQuery(string.Format("UPDATE EXCEPTIONAL_USE_POLICY_PARAM SET CREATED_DATE = to_date('{0}', 'dd/MM/yyyy') WHERE ID = '{1}' ", DATE, ID));
}
// if both values were changed
if (oldName != NAME && oldCreated != DATE)
{
GeneralDbExecuterService.executeSqlNonQuery(string.Format("UPDATE EXCEPTIONAL_USE_POLICY_PARAM SET NAME = '{0}', CREATED_DATE = to_date('{2}', 'dd/MM/yyyy') WHERE ID = '{1}' ", NAME, ID, DATE));
}
My question is, how can I make it more modular?
For example if 2 more columns are added its going to raise my IFs by few if not dozens. What is the best way to achieve that kind of dynamic approach? And is that even possible?. Thanks
edit: my main goal is to be able to detect what/where change has happened, and query the specific columns/values . ( basically its what I did) im just asking if theres a better way because if I were to add 5 more columns, I'd end up adding 40 more if statements..
If you use Entity Framework, rather than raw SQL, then you won't need to have any if statements at all. Your method would take an entity, and your code would just get the existing entity out of the database, and set the properties from the incoming one, irrespective of whether or not they have changed (air code, assumptions made about how you set up your model, etc)...
private async Task Update(PolicyParam p) {
PolicyParam existing = await dbContext.PolicyParams.Single(pp => pp.Id == p.Id);
existing.Date = p.Date;
existing.Name = p.Name;
// Update other properties here
await dbContext.SaveChangesAsync();
}
If you add another column, you just add one more line of code above.
EF has a zillion other benefits, like cleaner code, less chance of SQL injection, etc.

Comparing Sql Table Data on Visual

I am making a basic patient record system on visual studio (windows form application, c#).
When a user tries to insert the same firstname and surname, the application should give an error like:
You can't insert the same name twice.
I just don't know how to get data directly from sql on visual . Can anyone help ?
Make Firstname and lastname as primerykey combine in your db table, that will not allow duplicate... but making names as primary key is not good practice because may two patients have same first and last names
I hope this code helps.
I have assumed that you are using Entity Framework
var newPatient = ...;
if
(
Context.Patients.Count
(
x=>
x.Name==newPatient.Name &&
x.Family==newPatient.Family
) > 0
)
MessageBox.Show("This is an existing patient");
Edit (Based on your comment):
var newPatient= new Patient();
newPatient.Name = textBox1.Text;
newPatient.Family = textBox2.Text;
if
(
Ort.Grid.Count
(
x=>
x.Name==newPatient.Name &&
x.Family==newPatient.Family
) > 0
)
MessageBox.Show("This is an existing patient");

EF 5 Conditional Mapping

I'm using EF 5 Database first approach in my MVC application. all of my tables uses a Field called Deleted which is a boolean field to mark a record is deleted.
I'm trying to get rid of the requirement of having to check Deleted == false every time I query my database. The very straightforward way of doing this is to use a conditional mapping in the edmx file where EF always return data that are not deleted. That's all good.
But the problem of doing this condition mapping is that, when I want to allow the user to delete some record for e.g Address from their address book I don't have access to Delete field from EF as I used it in the conditional mapping and therefore I have to look for another option to allow user to delete a record.
The way I thought is to create a stored proc that handle the delete query and call it when I want to delete the record.
Is there a better way of doing this? Is it possible to make the Delete field accessible even it is used in the conditional mapping?
I have a working solution for Soft Delete in Entity Framework Code First that may help.
The key is that you add a discriminator to every model that you want to be able to soft delete. In code first that is done like this:
modelBuilder.Entity<Foo>().Map(m => m.Requires("IsDeleted").HasValue(false));
This makes it invisible to the context and therefore you have to do the deletes using sql.
If this is the equivalent of your "conditional mapping" in Database First then one way to modify the sql is to override SaveChanges and run sql from there:
public override int SaveChanges()
{
foreach (var entry in ChangeTracker.Entries()
.Where(p => p.State == EntityState.Deleted
&& p.Entity is ModelBase))//I do have a base class for entities with a single
//"ID" property - all my entities derive from this,
//but you could use ISoftDelete here
SoftDelete(entry);
return base.SaveChanges();
}
private void SoftDelete(DbEntityEntry entry)
{
var e = entry.Entity as ModelBase;
string tableName = GetTableName(e.GetType());
Database.ExecuteSqlCommand(
String.Format("UPDATE {0} SET IsDeleted = 1 WHERE ID = #id", tableName)
, new SqlParameter("id", e.ID));
//Marking it Unchanged prevents the hard delete
//entry.State = EntityState.Unchanged;
//So does setting it to Detached:
//And that is what EF does when it deletes an item
//http://msdn.microsoft.com/en-us/data/jj592676.aspx
entry.State = EntityState.Detached;
}
Method used to Get Table Name explained here
That is the way I used to do it. Probably irrelevant to your Database First approach in EF5, but I have now moved to doing it in stored procedures. EF6 Code First generates CreateStoredProcedure calls in Migration files. I replace these with this.CreateDeleteProcedure("dbo.Foo_Delete", "[dbo].[Foos]"); - which is a call to my own extension method:
public static class MigrationExtensions
{
internal static string DeleteSqlFormat
{
//I also hard delete anything deleted more than a day ago in the same table
get { return "DELETE FROM {0} WHERE IsDeleted = 1 AND DATEADD(DAY, 1, DeletedAt) < GETUTCDATE(); UPDATE {0} SET IsDeleted = 1, DeletedAt = GETUTCDATE() WHERE ID = #ID;"; }
}
internal static void CreateDeleteProcedure(this DbMigration migration, string procName, string tableName)
{
migration.CreateStoredProcedure(
procName,
p => new
{
ID = p.Int(),
},
body:
string.Format(MigrationExtensions.DeleteSqlFormat, tableName)
);
}
}

EntityFramework 4.1, context.Entities.Add sometimes set FK to NULL

I have this weird problem that has burned way more hours than it should.
My main question is this:
What may cause EF 4.1 Code First to set a foreign key to NULL when an entity is added?
The problem is this: I have a list of users on file, and these users must be inserted to my database if they're not already there.
I have something like this:
foreach (var u in usersFromFile) {
var userProfile = context.Users
.FirstOrDefault(user=>
user.EmployeeId == u.EmployeeId && user.CompanyId == 1);
if (userProfile == null) {
User newUser = new User();
newUser.EmployeeId = u.EmployeeId;
newUser.CompanyId = 1;
context.Users.Add(newUser); //This will sometimes set CompanyId = NULL
}
}
context.SaveChanges();
Some users won't be added to the Users table correctly.
They get CompanyId == NULL, and as such they do not belong to the company.
I also tried injecting SQL directly like so:
var query = #"INSERT INTO [dbo].[Users]
([CompanyId],[EmployeeId]) VALUES (3,#emplid)";
context.Database.ExecuteSqlCommand(query, new SqlParameter[] {
new SqlParameter("emplid", u.EmployeeId)});
I have tried to access the Users list on the Company object. That does not work.
I have tried to use context.Users.Create() instead of new User(). Does not change anything.
I have tried to inject SQL, still the same problem. That exact SQL works, if ran from the Studio Manager.
I have tried to context.SaveChanges() after each add, nothing changed.
I know for a fact that the state of the entity about to be added is correct, also in the cases where CompanyId is set to NULL.
Could there be something with my underlying database?
Thank you so much for your time and help!
Try the following:
foreach (var u in usersFromFile) {
if (context.Users.Any(
user=>
user.EmployeeId == u.EmployeeId && user.CompanyId == 1)
)
{
User newUser = new User();
newUser.EmployeeId = u.EmployeeId;
newUser.CompanyId = 1;
context.Users.Add(newUser); //This will sometimes set CompanyId = NULL
}
}
context.SaveChanges();
The Any() function checks wether a user based on the given query exists.
Also, don't forget to add the context.savechanges to make sure every added record gets put in the database.
Lastly, you checked if user.CompanyId = 1, should be == 1
I ended up transforming the list of users to a series of SQL statemens, and running them through context.Database.ExecuteSqlCommand(sql).
It's dirty but it works.
If anyone has any good ideas as to why the FK CompanyId on the user entity is sometimes set to NULL I'd we very happy if you share your ideas.

Quick way to detect if a DataContext table or view exists

Currently, I'm developing an application that depends on (and thus connects to) various databases via LINQ-to-SQL. For one of the databases, the connection string may vary and is thus configurable - however, the schema of this database is identical for all connection strings.
Because of the configurable connection string, I want to validate the DataContext during the startup of my application, to make sure that all tables and views my application uses, are available.
The Table<T> objects in the DataContext object are always initialized - even if the corresponding SQL table or view doesn't have any records.
So then. Currently, the validation check is performed as follows:
bool valid = _dataContext.Articles.Count() > 0
&& _dataContext.Customers.Count() > 0
&& _dataContext.Orders.Count() > 0;
While this does work, the determination of the value of valid takes quite some time (every record of each Table is touched), which ultimately results in a time out. So, is there a faster, more reliable way to determine whether or not a Table<T> of a certain DataContext really exists as a table in the corresponding database?
Here is an (untested) idea:
Grab the name of your table. You can hard code it in, or you can grab it programmatically via
TableAttribute attribute = (TableAttribute)typeof(MyTableObject)
.GetCustomAttributes(typeof(TableAttribute), true)
.Single();
string name = attribute.Name;
MyTableObject is the LINQ-to-SQL generated object contained in your Table, i.e., the generic parameter T in Table<T>.
(TableAttribute is in System.Data.Linq.Mapping.)
Use the DataContext.ExecuteQuery method as in
var db = new MyDataContext();
var results = db.ExecuteQuery<string>("SELECT name FROM dbo.sysobjects WHERE xtype = 'U'");
bool hasTable = results.Any(s => "dbo." + s == name);
A slight change on Jason's answer (I gave him an upvote :))
public bool TableExistsInDatabase<T>()
{
TableAttribute attribute = (TableAttribute)typeof(T)
.GetCustomAttributes(typeof(TableAttribute), true)
.Single();
var result = ExecuteQuery<bool>(
String.Format(
"IF OBJECT_ID('{0}', 'U') IS NOT NULL
SELECT CAST(1 AS BIT) ELSE
SELECT CAST(0 AS BIT)", attribute.Name));
return result.First();
}

Categories