I have two table BuildGroup and table DocumentTemplate. DocumentTemplate table has BuildGroupId as foreign key which is nullable. In a certain senario I update BuildGroupId in DocumentTemplate table.
public bool EditDocTempForBldGrp(int docId, int bldGrpId)
{
try
{
using (ISession session = Document.OpenSession())
{
using (ITransaction transaction = session.BeginTransaction())
{
HSDocumentTemplate objDocBO = new HSDocumentTemplate();
objDocBO = GetDocumentDetailsById(docId);
HSBuildGroup objBldGrp = new HSBuildGroup();
if (bldGrpId != 0)
{
objBldGrp.Id = bldGrpId;
}
else
{
//int ? bldid = null;
//objDocBO.HSBuildGroup.Id = null;
//objDocBO.HSBuildGroup.Id = DBNull.Value;
//objDocBO.HSBuildGroup.Id = -1;
}
objDocBO.HSBuildGroup = objBldGrp;
session.Update(objDocBO);
transaction.Commit();
}
}
return true;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return false;
}
}
In another senario I need to set BuildGroupId in DocumentTemplate table again to
dbnull.value. I tried with different cases as in else block. It giving the error : Cannot
implicitly convert type 'System.DBNull' to 'int'.
How can I update a foreign key value with NULL? Any help will be appreciated.
A few observations:
You should not assign the Id to a HSBuildGroup object, but instead load the instance via Session.Load() in case the bldGrpId is not 0.
You can just set the build group of a document to null like this:
objDocBO.HSBuildGroup = null;
NHibernate will take care of the rest.
Hope that helps.
Use Session.Load and null as Kay Herzam said.
You must to be sure than the document exist to call session.Load. Example:
public bool EditDocTempForBldGrp(int docId, int bldGrpId)
{
try
{
using (ISession session = Document.OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
session.Get<HSDocumentTemplate>(docId).HSBuildGroup
= bldGrpId = 0 ? null : session.Load<HSBuildGroup>(bldGrpId);
transaction.Commit();
}
}
}
This way nhibernate will execute something like,
select ... from DocumentTemplate where DocId = ..;
UPDATE DocumentTemplate SET .... , BuildGroupId = null where DocumentId = XX;
or
select ... from DocumentTemplate where DocId = ..;
UPDATE DocumentTemplate SET .... , BuildGroupId = YY where DocumentId = XX;
Note there is no select for BuildGroup to the database.
If you are not sure about the existence of the build group, your code should look like:
public bool EditDocTempForBldGrp(int docId, int bldGrpId)
{
try
{
using (ISession session = Document.OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
session.Get<HSDocumentTemplate>(docId).HSBuildGroup
= session.Get<HSBuildGroup>(bldGrpId);
transaction.Commit();
}
}
}
This way nhibernate will execute something like,
select ... from DocumentTemplate where DocId = ..;
SELECT .... FROM BuildGroup where buildgroupid = ZZ;
UPDATE DocumentTemplate SET .... , BuildGroupId = null where DocumentId = XX;
Get automatically returns null if the object doesn't exist.
Finally you don't need to call Session.Update() this is for reattaching an entity. Everything associated to a Session will be flushed when you commit the transaction.
Related
I'm trying to update two entities at the same time but the change is not applying and I think that when I try to return the update entity it doesn't even found it.
Here is my Razor view:
public IActionResult OnPost()
{
if (!ModelState.IsValid)
{
return Page();
}
repositorioFamiliar.Actualizar(Familiar);
return RedirectToPage("/Familiares/DetalleFamiliar", new { IdPaciente = Familiar.IdPaciente });
}
Here is my update function:
public FamiliaresPer Actualizar(FamiliaresPer familiar)
{
var familiarActualizar = (from f in _context.Familiars.Where(p => p.IdFamiliar == familiar.IdFamiliar) select f).FirstOrDefault();
if (familiarActualizar != null)
{
familiarActualizar.Correo = familiar.Correo;
_context.Update(familiarActualizar);
_context.SaveChanges();
}
var personaActualizar = (from p in _context.Personas.Where(p => p.Id == familiar.IdPersona) select p).FirstOrDefault();
if (personaActualizar != null)
{
personaActualizar.Telefono = familiar.Telefono;
_context.Update(personaActualizar);
_context.SaveChanges();
}
var familiares = from p in _context.Familiars
from p1 in _context.Personas
where p.IdPaciente == familiar.IdPaciente
where p.IdPersona == p1.IdPersona
select new FamiliaresPer()
{
IdFamiliar = p.IdFamiliar,
IdPaciente = p.IdPaciente,
IdPersona = p1.IdPersona,
Id = p1.Id,
Nombres = p1.Nombres,
Apellidos = p1.Apellidos,
Genero = p1.Genero,
Telefono = p1.Telefono,
Parentesco = p.Parentesco,
Correo = p.Correo,
};
FamiliaresPer familiaresPer = familiares.FirstOrDefault();
return familiaresPer;
}
When I submit the form I get an error
NullReferenceException: Object reference not set to an instance of an object
And the link shows the IdPaciente = 0 when it should use the same IdPaciente of the updated entity (which the Id never changes).
In your OnPost( ) Action Method, you used repositorioFamiliar.Actualizar(Familiar);
but it looks like you didn't define 'Familiar'.
In addition, when I look at your code. I can give you an advice. Let's say your first update was done correctly and you got an error in the second update case. But you want both to be updated at the same time. Assume that the first object is updated in the database but the second one isn't. This is a problem, right? Unit of Work design pattern is very useful to solve this.
In brief, The approach should be to do SaveChanges() after both update processes are completed so there will be no changes in the database until both updates are completed.
Gridview is not populating any data from Sqlite database while saving the data in to database. Logcat is not generating any error also.
My DB is.
public Cursor getAllRows() {
SQLiteDatabase db = this.getReadableDatabase();
//String where = null;
Cursor c = db.rawQuery("SELECT * FROM " + DATAALL_TABLE, null);
if (c != null) {
c.moveToFirst();
}
return c;
}
Mainactivity.
public void populateListView() {
Cursor cursor = db.getAllRows();
String[] fromFieldNames = new String[] {
DBHelper.COURSES_KEY_FIELD_ID1, DBHelper.FIELD_MATERIALDESC, DBHelper.FIELD_MATERIALNUM
};
int[] toViewIDs = new int[] {
R.id.textView1, R.id.textView3, R.id.textView2
};
SimpleCursorAdapter myCursorAdapter;
myCursorAdapter = new SimpleCursorAdapter(getBaseContext(), android.R.layout.activity_list_item, cursor, fromFieldNames, toViewIDs, 0);
GridView myList = (GridView) findViewById(R.id.gridView1);
myList.setAdapter(myCursorAdapter);
}
Post to the honorable member #MikeT advise its works fine but need alignment ,
as is
expected format
Your issue, assuming that there is data in the table, is likely that R.id.textView1 .... 3 are nothing to do with the layout passed to the SimpleCursorAdapter. i.e. Your issue is likely to do with the combination of the layout passed to the SimpleCursorAdapter and the Id's of the views passed as the to id's.
If you were to use :-
gridview = this.findViewById(R.id.gridView1);
csr = DBHelper.getAllRows();
myCursorAdapter = new SimpleCursorAdapter(
getBaseContext(),
//android.R.layout.simple_list_item_2,
android.R.layout.activity_list_item,
csr,
new String[]{
SO50674769DBHelper.COURSES_KEY_FIELD_ID1
//SO50674769DBHelper.FIELD_MATERIALDESC,
//SO50674769DBHelper.FIELD_MATERIALNUM
},
new int[]{android.R.id.text1}, //<<<< ID of the available view
0
);
gridview.setAdapter(myCursorAdapter);
Then result would be along the lines of :-
Changing to use a different stock layout and 2 fields as per :-
gridview = this.findViewById(R.id.gridView1);
csr = DBHelper.getAllRows();
myCursorAdapter = new SimpleCursorAdapter(
getBaseContext(),
android.R.layout.simple_list_item_2,
//android.R.layout.activity_list_item, //<<<< Changed Layout
csr,
new String[]{
SO50674769DBHelper.COURSES_KEY_FIELD_ID1,
SO50674769DBHelper.FIELD_MATERIALDESC,
//SO50674769DBHelper.FIELD_MATERIALNUM
},
new int[]{android.R.id.text1, android.R.id.text2}, //<<<< ID's of the 2 views
0
);
gridview.setAdapter(myCursorAdapter);
Note The DatabaseHelper class is so named for my convenience.
Would result in :-
As such I suspect that you need to change the layout to a one of your own.
Additionally, as hinted at your getAllRows method is not at all ideal.
Checking for a null Cursor is useless as a Cursor returned from rawQuery will not be null. It may be empty in which case the Cursor getCount method would return 0 ().
moveToFirst is also a waste.
Simply have :-
public Cursor getAllRows() {
SQLiteDatabase db = this.getReadableDatabase();
return db.rawQuery("SELECT * FROM " + DATAALL_TABLE, null);
}
I have a list of users in my list view which is populated by retrieving data from documentum . If I click on any row of this least (each row represent one user) I should be able to see all of their information listed down .(This is my problem )
public void selectedItemFromListView(){
selected = lwAllUserGrp.getSelectionModel().getSelectedItem();
System.out.println(selected);
String query =" select * from dm_user where user_name = '#aclName'" ;
String test = query.replace("#aclname", selected);
GetDataWithDqlProfile(_session , query , "user_login_name" , "user_address" , "user_state" );
System.out.println(user.getAddress());
System.out.println(user.getState());
System.out.println(user.getUsername());
}
if I click on a row of list view I can successfully see who is selected and I need to retrieve all the other attributes of that username (same person) from documentum via DQL .
private void GetDataWithDqlProfile(IDfSession session, String Query, String username , String address , String state ) {
try {
IDfQuery UpdateQuery = new DfQuery();
UpdateQuery.setDQL(Query);
IDfCollection col = UpdateQuery.execute(_session, IDfQuery.DF_QUERY);
user.setAddress(col.getString(username));
user.setUsername(col.getString(address));
user.setState(col.getString(state));
col.close();
} catch (Exception e) {
Alert alert = new Alert(Alert.AlertType.ERROR, e.getMessage());
alert.showAndWait();
Logs.WriteLog(LoginController.Repository + ",User:" + LoginController.Username, "DQL Query", e.toString());
e.getStackTrace();
}
and my output is :
User's name
null
null
null
I've tried the DQL query in DQL tester and it works well
In order to fetch rows from IDfCollection you have to call next() on the collection object. This method both advances to the next row and returns a boolean if successful. Use a boolean test (e.g., while or if) to iterate, like this:
IDfCollection col = UpdateQuery.execute(_session, IDfQuery.DF_QUERY);
if (col.next()) {
user.setAddress(col.getString(username));
user.setUsername(col.getString(address));
user.setState(col.getString(state));
}
col.close();
The iteration is necessary even if the collection contains only one row. In other words, you need to manually advance to the first row.
1) As #eiviamu already mentioned, you have to call IDfCollection.next() to get the next row.
2) Your code, among other problems, has one documentum-related: closing of collection must happen always in finally block.
Otherwise you can get unclosed collection which might lead to memory leaks and weird application behavior (e.g. if I'm not mistaken there are 9 simultaneous open collections are allowed for one DCTM session by default, and if you exceed this limit an exception will be thrown)
For those of you referring to this question later here is how I solved the problem :
public ArrayList<User> GetDataWithDqlpro(IDfSession session, String Query, String username , String state , String address) {
try {
IDfQuery UpdateQuery = new DfQuery();
UpdateQuery.setDQL(Query);
IDfCollection col = UpdateQuery.execute(_session, IDfQuery.DF_QUERY);
while (col.next()) {
list.add( new User(col.getString(username),col.getString(address) , col.getString(state)));
}
col.close();
}catch (Exception e) {
Alert alert = new Alert(Alert.AlertType.ERROR, e.getMessage());
alert.showAndWait();
Logs.WriteLog(LoginController.Repository + ",User:" + LoginController.Username, "DQL Query", e.toString());
e.getStackTrace();
}
return (ArrayList<User>) list;
}
public void selectedItemFromListView(){
selected = lwAllUserGrp.getSelectionModel().getSelectedItem();
System.out.println(selected);
String Query = "select user_login_name , user_state , user_address from dm_user where user_login_name ='#aclname'";
Query = Query.replace("#aclname",selected );
ArrayList<User> allUserNames = GetDataWithDqlpro(_session, Query, "user_login_name","user_address","user_state");
for (int i = 0 ; i <= allUserNames.size()-1 ; i++ ){
if (selected.compareToIgnoreCase(allUserNames.get(i).getUsername() ) == 0){
System.out.println(allUserNames.get(i).getState() );
System.out.println(allUserNames.get(i).getAddress() );
System.out.println(allUserNames.get(i).getUsername() );
}
}
}
Worth mentioning that I have a class called User with constructor and get and set methods
I hope it will help some one :)
I've got data returned from my JavaScript client that just includes the data that has changed. That is, I may have an array with each row containing 10 columns of JSON downloaded, but on the Update, only the data that is returned to me is the data that got updated. On my update, I only want to update those columns that are changed (not all of them).
In other words, I have code like below but because I'm passing in an instance of the "President" class, I have no way of knowing what actually came in on the original JSON.
How can I just update what comes into my MVC3 update method and not all columns. That is, 8 of the columns may not come in and will be null in the "data" parameter passed in. I don't want to wipe out all my data because of that.
[HttpPost]
public JsonResult Update(President data)
{
bool success = false;
string message = "no record found";
if (data != null && data.Id > 0)
{
using (var db = new USPresidentsDb())
{
var rec = db.Presidents.FirstOrDefault(a => a.Id == data.Id);
rec.FirstName = data.FirstName;
db.SaveChanges();
success = true;
message = "Update method called successfully";
}
}
return Json(new
{
data,
success,
message
});
}
rec.FirstName = data.FirstName ?? rec.FirstName;
I would use reflection in this case because the code will be too messy like
if (data.FirstName != null)
rec.FirstName = data.FirstName
.
.
.
and so on for all the fields
Using reflection, it would be easier to do this. See this method
public static void CopyOnlyModifiedData<T>(T source, ref T destination)
{
foreach (var propertyInfo in source.GetType().GetProperties())
{
object value = propertyInfo.GetValue(source, null);
if (value!= null && !value.GetType().IsValueType)
{
destination.GetType().GetProperty(propertyInfo.Name, value.GetType()).SetValue(destination, value, null);
}
}
}
USAGE
CopyOnlyModifiedData<President>(data, ref rec);
Please mind that, this won't work for value type properties.
I try to insert hundreds of records into empty database table using TableDirect type of SqlCeCommand. The problem is I get an exception SqlCeException "Unspecified error" when calling SqlCeResultSet::Insert. Below is my code. Any hints?
Thanks
public bool StoreEventsDB2(List<DAO.Event> events)
{
try
{
SqlCeCommand command = new SqlCeCommand("Event");
command.CommandType = System.Data.CommandType.TableDirect;
SqlCeResultSet rs = _databaseManager.ExecuteResultSet(command, ResultSetOptions.Updatable | ResultSetOptions.Scrollable );
foreach (DAO.Event theEvent in events)
{
SqlCeUpdatableRecord record = rs.CreateRecord();
record.SetInt32( 0, theEvent.ID );
record.SetInt32( 1, theEvent.ParentID);
record.SetString(2, theEvent.Name);
record.SetDateTime(3, theEvent.DateTime);
record.SetDateTime(4, theEvent.LastSynced);
record.SetInt32(5, theEvent.LastSyncedTS);
record.SetString(6, theEvent.VenueName);
record.SetBoolean(7, theEvent.IsParentEvent);
record.SetDateTime(11, DateTime.Now);
rs.Insert(record);
}
}
catch (SqlCeException e)
{
Log.Logger.GetLogger().Log(Log.Logger.LogLevel.ERROR, "[EventManager::StoreEventsDB] error: {0}", e.Message);
return false;
}
catch (Exception e)
{
Log.Logger.GetLogger().Log(Log.Logger.LogLevel.ERROR, "[EventManager::StoreEventsDB] error: {0}", e.Message);
return false;
}
return true;
}
I am unsure how your connection is managed with the database manager which could be the culprit - make sure you are using one connection (sqlce doesn't play nice). Also the results set option "ResultSetOption.Scrollable" is not needed (at least I have never used it for an insert).
Below is the syntax I use when doing direct table inserts. Every database/data access object is wrapped in a using statement to dispose of objects after use - this is very important especially with the compact framework and sqlce as the garbage collection is less than ideal (you WILL get out of memory exceptions!). I have added a transaction to your code also so that the option is all or nothing.
Hope this helps:
using (var transaction = connection.BeginTransaction())
{
using (var command = connection.CreateCommand())
{
command.Transaction = transaction;
command.CommandType = CommandType.TableDirect;
command.CommandText = "Event";
using (var rs = command.ExecuteResultSet(ResultSetOptions.Updatable))
{
var record = rs.CreateRecord();
foreach (DAO.Event theEvent in events)
{
record.SetInt32(0, theEvent.ID);
record.SetInt32(1, theEvent.ParentID);
record.SetString(2, theEvent.Name);
record.SetDateTime(3, theEvent.DateTime);
record.SetDateTime(4, theEvent.LastSynced);
record.SetInt32(5, theEvent.LastSyncedTS);
record.SetString(6, theEvent.VenueName);
record.SetBoolean(7, theEvent.IsParentEvent);
record.SetDateTime(11, DateTime.Now);
rs.Insert(record);
}
}
transaction.Commit();
}
}