EF6 Nested Transactions are not supported - c#

I'm trying to make a simple database insert for just one table, the insert and the connections are working perfectly.The problem appears only when the exceptions arise for entering bad data.
Here is my code: (using MySql and EF6)
using (MaintenanceDB db = new MaintenanceDB())
{
try
{
employee employee = new employee
{
ID = idTBA.textBox.Text,
EName = enTBA.textBox.Text,
AName = anTBA.textBox.Text,
CareerCode = careerCodeCBA.comboBox.SelectedItem.ToString(),
Specialization = specTBA.textBox.Text,
Mobile = mobileTBA.textBox.Text,
Telephone = teleTBA.textBox.Text,
Email = emailTBA.textBox.Text
};
db.employees.Add(employee);
db.SaveChanges();
}
catch (DbUpdateException exception)
{
MessageBox.Show(exception.InnerException.InnerException.Message);
}
catch (EntityException exception)
{
MessageBox.Show(exception.InnerException.Message);
}
}
so if the data entered correctly everything is smooth and fine, but if I entered duplicate ID for example the first time it's going to the first catch block and tell me there is a duplicate , at this point there is something wrong, it seems the connection isn't closed here (Despite using finally and dispose on db), the next time I hit the save button the error "Nested Transactions are not supported" appears, and then the db closes and I'm able to enter new data!
I tried opening the connection manually or starting a transaction and closing it manually as I found in few posts here but nothing seems to solve the problem

It seems like a mysql bug...., #71502
[27 Feb 15:54] Raif Atef
This bug is due to a bug in the MySqlTransaction class.

Related

c# windowsform , What is next step before deployment?

Just finished my Winforms program for Clinics with database in sql managment Studio.
My Connection is ADO.NET Entity Data Model I mean edmx. I want to ask you guys what is next step and asking you if you see any injection problem
and how should I protect from Injection. All my code is Linq and I belive with Linq you get less problem of Injections.
My questions are three questions:
1) What kind of changes must I do in settings in my Visual project before deploying alaive on real server.
Is there any changes to do in Properity of my winforms Project? Becouse now this will be Production project.
2) My second question is, Do you see guys any lack of Security in my code when I add a new person, or when I search a person? And How should I do for the security sake?
See my some of my code below please
3) Is (ADO.NET Entity Data Model, ADO.NET Entity Data Model) normal to use for such kind of big system?
becouse my connectionstring is in App.config and it's very long string like this below and its geting me litle scared.. ;)
<add name="ClinicEntities" connectionString="metadata=res://*/MyHealthModel.csdl|res://*/MyHealthModel.ssdl|res://*/MyHealthModel.msl;provider=System.Data.SqlClient;provider connection string="data source=MyComputerName;initial catalog=ClinicDb;user id=***;password=*****;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" /></connectionStrings>
Here is some of my code:
When searching person:
private void SearchPatient()
{
try
{
using (ClinicEntities db = new ClinicEntities())
{
if(txtIdCardnr.Text != string.Empty)
{
string IdCard = txtIdCardnr.Text.Trim();
var patId = db.Patient.Where(x => x.IdentityCardNr == IdCard).FirstOrDefault();
if(patId != null)
{
var reservation = (from u in db.Registration
join p in db.Patient on u.PatientId equals p.PatientId
join ....... you got the idea
where ......
select new
{
ReservationNr = u.ReservNr,
ReservationDate = u.ReservationDate,
........
}
).ToList();
dgvReservations.DataSource = reservation;
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
Exception inner = ex.InnerException;
while (inner != null)
{
MessageBox.Show(inner.Message);
inner = inner.InnerException;
}
}
}
And for adding new reservation:
private async void AddReservation()
{
try
{
using (ClinicEntities db = new ClinicEntities())
{
if (IsValidated())
{
Reservation pat = new Reservation();
pat.SymptomId = Convert.ToInt32(cmbSymptom.SelectedValue);
pat.SymptonDate = Convert.ToDateTime(dateTimePicker1.Value.Date);
pat.SymptonTime = txtTime.Text.Trim();
pat.Notes = txtNoteEmg.Text.Trim();
pat.RegisterdBy = StaffId;
pat.PatientId = PatientId;
db.Reservation.Add(pat);
await db.SaveChangesAsync();
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
Exception inner = ex.InnerException;
while (inner != null)
{
MessageBox.Show(inner.Message);
inner = inner.InnerException;
}
}
}
So, du you see guys any lack of security in my code? Thank you again for helping me to get all three questions.
StackOverflow is not the place for code review (but there is a stack exchange site for code review and your question may be on topic there)
1) I'm not really sure how the server comes into this equation; surely it's only offering this winforms app for download, like any other file. No changes should be needed
2) I see an unencrypted plain text password in your config file, but whether you care or not is another matter. It could be that even if the user did open the local db with the password they found and have a look around they can't do any real damage. Now if that password is the same as your production server it might be more of an issue... The LINQ you have written to do your db access is immune to SQL injection. The only way to make it liable is to execute raw sql command that have had user provided values concatenated into them
3) I'm not sure StackOverflow is the place to seek help with a phobia of long connection strings. It works; leave it alone (other than encrypting the password maybe)

Adding and removing data from the db using Entity Framework

I have several tables in the DB and I want to remove all the data and repopulate the tables and only then perform a save changes (because in case the save fails I want to return to the old data).
when I remove the data from the DB and then try to add the data into the DB it fails and says "Adding a relationship with an entity which is in the Deleted state is not allowed.", but when I remove the data then save and then add the new data and saves again, everything works fine..
here is my code if it helps understanding the problem
// create the new data
SomeDataHolder data = ... ;
// save some data to re-enter back after changes
List<User> usersSave = ctx.Users.ToList();
List<UserPreferences> userPrefsSave = ctx.UserPreferences.ToList();
//clear DB
ctx.UserCourses.RemoveRange(ctx.UserCourses);
ctx.Users.RemoveRange(ctx.Users);
ctx.Specializtions.RemoveRange(ctx.Specializtions);
ctx.Course_Predecessor.RemoveRange(ctx.Course_Predecessor);
ctx.Courses.RemoveRange(ctx.Courses);
ctx.Departments.RemoveRange(ctx.Departments);
ctx.GroupsDetails.RemoveRange(ctx.GroupsDetails);
ctx.LinkTable.RemoveRange(ctx.LinkTable);
this next line makes everything works, without this line the code will fail on next save
// ctx.SaveChanges();
updateDepartmentsCoursesSpecialization(ctx, data.Specializations);
updateCoursePredecessorsAndParallel(ctx, data.Predecessors);
updateGroupDetails(ctx, data.GroupDetails);
updateLectureToPractice(ctx, data.LinkLectureWithPractice);
ctx.Users.AddRange(usersSave);
ctx.UserPreferences.AddRange(userPrefsSave);
ctx.SaveChanges();
Here you have to use Transaction.B'cos you're doing more than one atomic operation on your code base.By using Transaction where you can Combine several operations into one transaction within the same context.If there is any failure within the transaction then all will be roll-backed.
Transaction code snippet is like this :
using (var ctx = new MyContext())
{
using (var dbContextTransaction = ctx.Database.BeginTransaction())
{
try
{
//1st operations here
ctx.GroupsDetails.RemoveRange(ctx.GroupsDetails);
ctx.LinkTable.RemoveRange(ctx.LinkTable);
ctx.SaveChanges();
//2nd operations here
ctx.Users.AddRange(usersSave);
ctx.UserPreferences.AddRange(userPrefsSave);
ctx.SaveChanges();
dbContextTransaction.Commit();
}
catch (Exception)
{
dbContextTransaction.Rollback();
}
}
}
You can refer this for more info : Working with Transactions

Nhibernate transaction locks a tabel

I have developed a WCF api which is using nHibernate. I am new to this. I have used session.update to take care of transaction. I have a for loop in which based on select condition I am updating a record ie. If A is present in tabel1 then I am updating the table else inserting a new entry.
I am getting "could not execute query." when trying to execute a select query on a table which was previously being updated by adding a new entry in the table.
What I think is, because I am using session.save(table1) and then trying select entries from that table I am getting an error. Since session.save temporarily locks the table I am not able to execute a select query on that table.
What can be the solution on this?
Update:
This the for loop I am using to check in the database for some field:
using (ITransaction tranx = session.BeginTransaction())
{
savefunction();
tranx.Commit();
}
Save function:
public void savefunction()
{
for (int i = 0; i < dictionary.Count; i++)
{
ICandidateAttachmentManager candidateAttach = new ManagerFactory().GetCandidateAttachmentManager();
CandidateAttachment attach = new CandidateAttachment();
attach = checkCV();
if(attach == null)
{
//insert new entry into table attach
session.save(attach);
}
}
}
checkCV function:
public void checkCV()
{
using (ICandidateAttachmentManager CandidateAttachmentManager = new ManagerFactory().GetCandidateAttachmentManager())
{
IList<CandidateAttachment> lstCandidateAttachment = CandidateAttachmentManager.GetByfkCandidateId(CandidateId);
if (lstCandidateAttachment.Count > 0)
{
CandidateAttachment attach = lstCandidateAttachment.Where(x => x.CandidateAttachementType.Id.Equals(FileType)).FirstOrDefault();
if (attach != null)
{
return null;
}
else
{
return "some string";
}
}
}
}
What happening here is in the for loop if say for i=2 the attach value comes to null that I am entering new entry into attach table. Then for i=3 when it enters checkCV function I get an error at this line:
IList lstCandidateAttachment =
CandidateAttachmentManager.GetByfkCandidateId(CandidateId);
I think it is because since I am using session.save and then trying to read the tabel contents I am unable to execute the query and table is locked till I commit my session. Between the beginTransaction and commit, the table associated with the object is locked. How can I achieve this? Any Ideas?
Update:
I read up on some of the post. It looks like I need to set isolation level for the transaction. But even after adding it doesn't seem to work. Here is how I tried to inplement it:
using (ITransaction tranx = session.BeginTransaction(IsolationLevel.ReadUncommitted))
{
saveDocument();
}
something I don't understand in your code is where you get your nHibernate session.
Indeed you use
new ManagerFactory().GetCandidateAttachmentManager();
and
using (ICandidateAttachmentManager CandidateAttachmentManager = new ManagerFactory().GetCandidateAttachmentManager())
so your ManagerFactory class provides you the ISession ?
then you do:
CandidateAttachment attach = new CandidateAttachment();
attach = checkCV();
but
checkCV() returns either a null or a string ?
Finally you should never do
Save()
but instead
SaveOrUpdate()
Hope that helps you resolving your issue.
Feel free to give more details

Oracle Entity Framework C#

I'm using an Oracle 11g database with the ADO.NET Entity Data Model. Every now and then I run into this error and I have no idea what's causing it. I'm assuming it's something in the EDMX file or the designer file for it but I can't seem to figure it out. I've deleted the model, added it, updated, etc multiple times and can't figure out the issue. It works on other pages but this one seems to be a problem.
This has happened before, but simply removing and re-adding the table worked. Any ideas on how to fix this?
using (ODSData.Entities entities = new Entities())
{
var info = from item in entities.ODS_VALIDATIONRULE
select item;
newPK = Convert.ToInt32(info.Max(p => p.VALIDATIONRULEID)) + 1;
try
{
ODS_VALIDATIONRULE newRule = new ODS_VALIDATIONRULE();
newRule.ALLOWNULLIND = isNull;
newRule.CREATEDATE = DateTime.Now;
newRule.FAILIND = isFail;
newRule.MAXVALUEFACTOR = max;
newRule.MINVALUEFACTOR = min;
newRule.RULEDESCRIPTION = description;
newRule.SOURCESYSTEM = source;
newRule.TABLENAME = table;
newRule.COLUMNNAME = column;
newRule.DATATYPE = datatype;
newRule.VALIDVALUELIST = valid;
newRule.VALIDATIONRULEID = newPK;
entities.AddToODS_VALIDATIONRULE(newRule);
entities.SaveChanges();
insertAccepted = true;
}
catch
{
// Log Error
}
The error I'm getting is this: "An error occurred while preparing the command definition. See the inner exception for details."
Inner Exception: "Operation is not valid due to the current state of the object."
Apparently the issue here was somewhere in the EDMX file and the way it read from Oracle. I deleted the table and recreated it in the DB as well as the EDMX and then added it back. It worked fine then.
The only thing I see that seems odd is you aren't using a sequence for your Pk value. You may try creating one and see if that helps at all.

Rows added to databank disappear after re-run of the program

I'm making a rather "simple" piece of software and at the moment I'm working with one table in my database and reading from the database works and now I was trying to implement inserting into the database, which seems to work as long as the program is running, but when I stop the program (stop debugging in VS) and launch it again, the rows don't seem to be in the database (already checked the .mdf database itself for the rows but they can't be found).
This is the piece of code:
public void saveKlant(klant nieuweKlant)
{
KlantGegevens newKlant = new KlantGegevens();
newKlant.klantNaam = nieuweKlant.naam;
newKlant.klantStraat = nieuweKlant.straat;
newKlant.klantPostcode = nieuweKlant.postcode;
newKlant.klantHuisNummer = nieuweKlant.huisnummer;
newKlant.klantGSM = nieuweKlant.gsm;
newKlant.klantTel = nieuweKlant.telnummer;
newKlant.klantGebDatum = nieuweKlant.gebDatum;
newKlant.klantEmail = nieuweKlant.email;
using (kapsalonEntities context = new kapsalonEntities())
{
try
{
context.KlantGegevens.AddObject(newKlant);
int test = context.SaveChanges();
}
catch
{
throw new InvalidOperationException("het object kon niet toegevoegd worden");
}
}
}
"test" equals 1 (so context.SaveCHanges() = 1) when running the program.
what would be the reason for the data to not be added persistently? since I do use a Context.SaveChanges()?
Thanks in advance.
It looks like you didn't check of the property where the database each time copies himself toi the debug directory. That's why you always get your default data again. Set the property to "if newer"

Categories

Resources