Different DBContexts possible at the Data access Layer? - c#

Here is my current problem. Lets say I have a DBConext for Customers called CustomerContext and on for Employees called EmployeeContext. I have them in two different DBContexts to keep it smaller and simplified. When I want to create a new customer, I call my Customers BLL(Business Logic Layer) which will in turn create a new instance of the CustomerContext. Now that context will be passed to a other related BLLs to verify the information and add their own records to the context to be inserted. when a context is passed into a BLL, that BLL will not save the changes to the context, the Parent level procedure will do that.
This works fine except when I pass the context to the Notes BLL. Here If I define the context as CustomerContext I am okay, but I need to also use this with EmployeeContext. How can I pass the Context in and determine which one to use at runtime? I tried passing it in as an object, but then if I try to add it to the table, I get object does not contain a definition for Note. Any suggestions would be greatly appreciated.
Here is a sample of what I want it to do, but I get an error on the moContext.Notes.Add(oNote); line, because its an object and not the context. moContext could be either CustomerContext or EmployeeContext.
object moContext;
bool mbContextCreatedLocal;
public NotesDAL(ref object pContext)
{
moContext = pContext;
mbContextCreatedLocal = false;
}
public void InsertNote(Note pNote)
{
Note oNote = null;
oNote = new Note()
{
Note = pNote.Note.Trim(),
NoteCategoryID = pNote.NoteCategoryID,
Title = (string.IsNullOrEmpty(pNote.Title) ? null : pNote.Title.Trim()),
};
moContext.Notes.Add(oNote);
if (mbContextCreatedLocal )
{
moContext.SaveChanges();
}
}

Related

Holding Values in an object for console application C#

I am currently writing an application where I am getting data from the DB and passing it to the object which will later be used to send the data off else where. The issue I am having in testing is that the data doesn't hold in the object as when it is used later, I get null value errors. I know we can store these in sessions, but I also know you can use objects and have done it before at previous jobs, but do not recall what I am missing to maintain the information. Would I need to pass the object(s) from method to method until the job is done?
the first sample here shows where it is prepping the object.
public void FtpInitialize()
{
_LogController.LogToFile(ValidateMessage.BeginInitialization);
//Loading FTPClient object with ClientInfo Object data we got from DataBase. FTPClient object is the object that sends the data.
_LogController.FTPTraceLogToFile();
ClientInfo = _RepositoryController.GetClientInfo(ClientInfo);
if (ClientInfo == null)
ClientInfo.ClientDataExists = false;
else
{
FTPClient.Host = ClientInfo.Host;
FTPClient.Port = ClientInfo.Port;
FTPClient.EncryptionMode = FtpEncryptionMode.Explicit;
FTPClient.Credentials = new NetworkCredential(ClientInfo.UserName, ClientInfo.Password);
FTPClient.DataConnectionType = FtpDataConnectionType.EPSV; //according library documentation, auto passive is broken as of 10/20/2016
FTPClient.EnableThreadSafeDataConnections = ClientInfo.EnableThreadSafeConnection;
FTPClient.DataConnectionConnectTimeout = ClientInfo.DataConnectionTimeout;
FTPClient.DataConnectionReadTimeout = ClientInfo.DataReadTimeout;
FTPClient.ConnectTimeout = ClientInfo.ConnectionTimeout;
FTPClient.ReadTimeout = ClientInfo.ReadTimeout;
FTPClient.SocketPollInterval = ClientInfo.SocketPollInterval;
FTPClient.SocketKeepAlive = ClientInfo.KeepSocketAlive;
FTPClient.ValidateCertificate += new FtpSslValidation(OnValidateCertificate);
_LogController.LogToFile(ValidateMessage.ClientDataLoaded);
ClientInfo.ClientDataExists = true;
}
}
then below when I hit this part, it shows as null
public bool SendData()
{
short errorCount = 0;
using (FTPClient)
{
if (ClientInfo.ClientDataExists)
{
This looks like you are using local variables in your methods. This is why the data "disappears".
For example if you are pulling data from your database you should have some kind of model class and container so that the data can persist until you are done with it.
EX: You have a database that contains information on people (name, dob, etc).
You should have a class that defines person and possibly a List to store said people. You call your database and pull X person objects into your List variable. You then can pass your List into the methods. Note: You can ditch the List (or whatever collection you use) if you are doing it one at a time.
The implementation of this really depends on how you want the objects to persist. If you know you will only pull one person object at a time you can declare var databasePerson from the database. Use the List if you will be pulling more information and then pop off the object when your are down with it.
Hope that helps.

Trouble Attaching an object to a Telerik OpenAccess Data Context

I am writing some tests to excersize the repository layer of a library built on Telerik OpenAccess ORM and am running into some problems with managing the Context.
I am creating a new RegionEntity object and adding it to the database. I use the using statement so that the context cleans up after itself. I additionally create a Detached copy of the added RegionEntity so that it can be re-attached to a context later on.
private RegionEntity AddTestRegionToTable()
{
String regionName = Guid.NewGuid().ToString();
RegionEntity newRegion = new RegionEntity () { /*...property assignment goes here ...*/ };
RegionEntity ret = null;
using (DbContext ctx = new DbContext())
{
ctx.Add(newRegion);
ctx.SaveChanges();
ret = ctx.CreateDetachedCopy<RegionEntity>(newRegion);
}
return ret;
}
So far ... no problem. In my TestMethod below I call the above method and receive a Detached RegionEntity. (I have pulled out my assert statements as they are inconsequential to the issue). I then pass the entity to the Respository method I want to test.
[TestMethod]
public void RemoveRegion_Success()
{
//
// Assemble
RegionEntity origEntity = AddTestRegionToTable();
//
// Act
deletedEntity = RegionRepository.RemoveEntity<RegionEntity>(origEntity);
//
// Assert
/* asserts go here */
}
For the sake of completeness, below I have included ALL the remaining code, exactly as it appears in my application. The repository methods are Generic (again ... should not be relevant to the issue). The first method is the one that is called by the test method, passing in the region as the entityToRemove parameter. This method, in turn calls the DBUtils method, GetContext(), that will either retrieve the DbContext from the entity, or ... if one is not able to be derived... create a new context to be used. In our example a new context is being created.
public class RegionRepository
{
public static T RemoveEntity<T>(T entityToRemove) where T : class
{
T ret = null;
using (DbContext ctx = DbUtils.GetContext<T>(entityToRemove))
{
ret = RemoveEntity<T>(ctx, entityToRemove);
ctx.SaveChanges();
}
return ret;
}
public static T RemoveEntity<T>(DbContext ctx, T entityToRemove) where T : class
{
//
// first chcek to see if the listingToUpdate is attached to the context
ObjectState state = OpenAccessContext.PersistenceState.GetState(entityToRemove);
//
//If the object is detached then attach it
if (state.HasFlag(ObjectState.Detached))
{
ctx.AttachCopy<T>(entityToRemove);
}
//
// confirm that the DETACHED flag is no longer present.
ObjectState state2 = OpenAccessContext.PersistenceState.GetState(entityToRemove);
if (state2.HasFlag(ObjectState.Detached))
{
throw new Exception("Unable to attach entity to context");
}
ctx.Delete(entityToRemove);
return entityToRemove;
}
}
public class DBUtils
{
public static DbContext GetContext<T>(T entity)
{
DbContext ret = OpenAccessContextBase.GetContext(entity) as DbContext;
if(ret == null)
{
ret = new DbContext();
}
return ret;
}
}
Anyway, the method then passes this context and the entity as parameters to an overload. This method takes the DbContext as an additional parameter (allows a single context to be used in multi-step workflows). So the context that is used should still be the one we extracted from the entity or created in our GetContext() method. I then check to see if the entity is attached to the context or not. In this scenario I AM getting a flag of "Detached" as one of the state flags (others are MaskLoaded | MaskManaged | MaskNoMask) so the process then attaches the entity to the context and upon the second check I confirm that the Detached flag is no longer present.
As it turns out the entity is NOT being attached ... and the exception is being thrown.
I have read the Telerik documentation on Detaching and attaching objects to a context ... Attaching and Detaching Objects
By design ObjectState is flags enum that contains both the basic values that form the persistent states of Data Access and the persistent states themselves.
In this enum, Detached is a value that participates in the three detached persistent states: DetachedClean, DetachedDirty, and DetachedNew. You can find more information about the values and the states in this article.
When you detach an object from the context, its state is DetachedClean. If at this point you change any of the properties, the state of the object will become DetachedDirty. If you attach the object back, it will remain in the state before the attachment. Simply put, the action of attaching the object does not change its state.
In other words, checking for Detached is the reason why you get the "Unable to attach entity to context" exception. This value will always be available in the state of your object.
As I am reading the code forward, on this line:
ctx.Delete(entityToRemove);
You will get an exception anyway, because Data Access does not allow you to delete objects that are retrieved through another instances of the context. The exception is:
InvalidOperationException: Object references between two different object scopes are not allowed.
I hope this helps.
-= EDIT =-
When you attach a certain object to an instance of the context and call the SaveChanges() method, Data Access will automatically decide whether to insert a new row in the database or to update an existing row. In this connection, the insert and update scenarios are handled by the Attach / Detach API.
Regarding the delete scenario, you have two options:
To retrieve the object from the database and to delete it through the Delete() method (and call SaveChanges()), like this:
var myObj = ctx.RegionEntities.First(r => r.Id == entityToRemove.Id);
ctx.Delete(myObj);
ctx.SaveChanges();
To use the BulkDelete feature like this:
var myObj = ctx.RegionEntities.Where(r => r.Id == entityToRemove.Id);
int deletedObjects = myObj.DeleteAll();
Something you need to consider with the first option is whether to call SaveChanges() after you attach the object. It is a good idea to do so if there are changes you would like to persist before deleting the object. Additionally, when you use the Delete() method of the context you need to commit the change through the SaveChanges() method before you dispose the current instance of the context. If you do not do this, the transaction will be rolled back, meaning that the object will not be deleted. Details about the transaction handling are available here.
The second option, Bulk Delete, executes the delete operations in a separate transaction upon the call to the DeleteAll() method. Therefore, any other uncommitted changes are not affected. Nevertheless, you need to consider a call to SaveChanges() after attaching the object, especially if the attached object and the deleted one are one and the same object.

How to access related objects after using statement has finished in Entity Framework?

I use the EF 3.5 in VS 2010. I have a method which returns a struct. In the struct there is an object armatuur. When the struct is returned i want to access the related objects from the armatuur instance.
However
the method returning the struct:
public LampPostDetail getLamppostInfo(int id)
{
LampPostDetail lpd;
lpd.xPos = 0;
lpd.ypos = 0;
lpd.armatuur = new Armatuur();
//get the info from object
using (var db = new OvisionDBEntities())
{
var objects = from o in db.Objects
where o.ObjectId == id
select o;
foreach (OVSL.Data.Object o in objects)
{
lpd.xPos = o.XCoordinatie;
lpd.ypos = o.YCoordinatie;
lpd.armatuur = o.Armatuur; //which is a table in my db
}
return lpd;
}
}
struct:
public struct LampPostDetail
{
#region [ Data Members (14)]
//lamppost info
public double? xPos;
public double? ypos;
//a lamppost can have several armaturen
public OVSL.Data.Armatuur armatuur; //is a table in my db
#endregion [ Data Members ]
}
when doing this in my client:
LampPostDetail lpd = client.getLamppostInfo(id);
string brand = lpd.armatuur.producer.name; //producer is related object of armatuur
I get a ObjectDisposedException. I understand that this happens because the LampPostDetail object is disposed after the using block is finished. But how do i get this to work? Retrieving all information I need (like brand name e.g.) before I return it to the client is not not an option.
The only thing that gets disposed here is the OvisionDBEntities context. After that, no lazy loading is possible. How to deal with that? In fact your question is: what can you do to feed a client with all data that are potentially required for user actions at any time? I see three or four options:
The standard way to enable access to navigation properties of entities after context disposal is calling Include: from o in db.Objects.Include("Armatuur.Producer")... But that's clearly not an option for you.
Let the context live and rely on lazy loading to fetch data on demand. This may be an option for you. But long-lived contexts may cause problems like gradually declining performance as the internal change track record grows, and stale cached data giving rise to refresh/reload statements scattered all over the place.
In stead of navigation properties/lazy loading fetch data on demand from a service/repository layer that uses context instances per call. I think this option could work well for you.
More a functional than a technical option: design use cases that can do with less data (so that Include may suffice after all). No one can take in a grid with thousands of rows and tens of columns. Well-designed user interaction can drastically reduce the amount of data that is pumped into a client (and I'm only at the beginning of getting this).
Its not you LampPostDetail that is getting disposed, it is the Armatuur object you retrieved from the database that it references, or an object that Armatuur is referencing.
I can see two options to getting around this. The first is to make the Entity context an optional parameter to your getLamppostInfo info method. Since you are using 3.5 you will have to do an overload to keep the orignal functionality:
public LampPostDetail getLamppostInfo(int id,OvisionDBEntities context)
{
...
try
{
OvisionDBEntities db;
if (context == null)
db = new OvisionDBEntities();
else
db = context;
...
}
finally
{
if (context == null && db != null)
db.Dispose() // or close maybe
}
retun lpd;
}
// Overloaded function to keep orignal functionality (C# 3.5 does not have
// optional parameters)
public LampPostDetail getLamppostInfo(int id)
{
return LampPostDetail(id,null)
}
Now you can call it as:
using (var db = new OvisionDBEntities())
{
LampPostDetail lpd = client.getLamppostInfo(id,db);
string brand = lpd.armatuur.producer.name;
}
And your objects will still exist when you try to reference them.
The other option is to detach your referenced objects from the entity context, before disposing of it.
db.Detach(o.Armatuur);
However, I don't believe that detaches any objects references by that object. So you would have to interate the reference trees and detach thoes objects as well.

Entity Framework - "The relationship between the two objects cannot be defined" error, but I think I'm using the same context

In my ViewModel I have some code like that:
public class OrderViewModel
{
private UserOrder order;
private DeliveryCentre deliveryCentre;
// This is my EF Container
private CatalogueContainer catalogue = new CatalogueContainer();
// do some stuff...
public void Save()
{
if (order == null)
{
order = catalogue.UserOrders.CreateObject();
}
// do some other stuff...
if ((deliveryCentre == null)
|| (deliveryCentre.Id != deliveryCentreId))
{
deliveryCentre = catalogue.DeliveryCentres.First(centre => centre.Id == deliveryCentreId);
//Causes a context error, not sure why...
order.DeliveryCentre= deliveryCentre;
}
catalogue.SaveChanges();
}
So when the delivery centre is new and the order is new, I am hit by the old "The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects" error, which seems a trifle unfair to me - I just can't figure out what I need to do to make them belong more to the same object context. I assume this is due to some fundamental misunderstanding of the behaviour of Entity Framework.
You are not disposing your context. It may be possible that one of the entities order or deliveryCentre is attached to an old context which still holds references to the entities. You can create and dispose your context with an using statement inside of the Save method instead to using it as a member variable:
public void Save()
{
using (var catalogue = new CatalogueContainer())
{
// your code...
}
}
And remove the private catalogue member.
The solution turned out to only be indirectly related to the error message- #Slauma asked about the //do stuff... placeholders and when I commented those out the error disappeared.
It turned out that there was another relationship there, where I was creating the object as this.Item = new Item() rather than using this.Item = catalogue.Items.CreateObject() so it was being created out of context and when it was added to the order, although the order itself was created from the local context, when the Item was added to it this was somehow dirtying up the context but for some reason this only showed up as a problem when I added the next related object.

C#: How to resolve this circular dependency?

I have a circular dependency in my code, and I'm not sure how to resolve it.
I am developing a game. A NPC has three components, responsible for thinking, sensing, and acting. These components need access to the NPC controller to get access to its model, but the controller needs these components to do anything. Thus, both take each other as arguments in their constructors.
ISenseNPC sense = new DefaultSenseNPC(controller, worldQueryEngine);
IThinkNPC think = new DefaultThinkNPC(sense);
IActNPC act = new DefaultActNPC(combatEngine, sense, controller);
controller = new ControllerNPC(act, think);
(The above example has the parameter simplified a bit.)
Without act and think, controller can't do anything, so I don't want to allow it to be initialized without them. The reverse is basically true as well. What should I do?
ControllerNPC using think and act to update its state in the world:
public class ControllerNPC {
// ...
public override void Update(long tick)
{
// ...
act.UpdateFromBehavior(CurrentBehavior, tick);
CurrentBehavior = think.TransitionState(CurrentBehavior, tick);
}
// ...
}
DefaultSenseNPC using controller to determine if it's colliding with anything:
public class DefaultSenseNPC {
// ...
public bool IsCollidingWithTarget()
{
return worldQuery.IsColliding(controller, model.Target);
}
// ...
}
Separate the model of the controller from the concrete controllerService using an interface.
This is about project references in domain driven design, I wrote a small blog about this problem some time earlier:
http://www.mellekoning.nl/index.php/2010/03/11/project-references-in-ddd/
Use two-phase construction, whereby the objects are constructed with null references to their related objects, and you then call set methods to set the references:
ISenseNPC sense = new DefaultSenseNPC(worldQueryEngine);
IThinkNPC think = new DefaultThinkNPC();
IActNPC act = new DefaultActNPC(combatEngine);
controller = new ControllerNPC();
sense.setController(controller);
think.setSense(sense);
act.setSense(sense);
act.setController(controller);
controller.setAct(act);
controller.setThink(think);
// And now the objects are ready to use.
Would it be possible to use events for some of the communication between objects?
From my understanding, the 1st and the main thing is: Controller should not know about thinking, sensing, acting...
I see you have something like 'Update' method for controller and (I guess) controller need to do something depending to current 'thinking','sensing','acting'.
For such case I would add 3 more components on a model level: 'ThinkModel', 'ActModel', 'SenseModel'. They should represent state of corresponding process and know nothing about other world.
Your controller should receive this information from components (Thinking, Acting, Sensing) by methods like 'DoAction', 'ThinkingAbout', 'FeelingSomething' and store it inside.
In the same time it should have a set of events like 'ActionOccured', 'ThinkingOccured', 'SenseingOccured' (last can be phrased like 'FeeledSomething'). These events should be:
fired in case of any state changed;
provide corresponding object model;
should be listened by components.
As a result you will have controller to know about models only, and each component to refer to all models AND controller. Components need to know nothing about each other. Controller need to know nothing about components. And you will be able to create your object in the way like this:
IThinkModel modelThinkg = new ThinkModel();
IActModel modelAct = new ActModel();
ISenseModel modelSense = new SenseModel();
IController controller = new Controller(modelThinkg, modelAct, modelSense);
ISenseNPC sense = new DefaultSenseNPC(controller);
IThinkNPC think = new DefaultThinkNPC(sense);
IActNPC act = new DefaultActNPC(combatEngine, sense, controller);
Constructor of each component can look like this:
class DefaultSenseNPC
{
DefaultSenseNPC(IController controller)
{
_controller = controller;
_contoller.ThinkingAbout += ContollerReceivedNewThinking;
}
private ContollerReceivedNewThinking(IModelThinking modelNewThink)
{
_modelNewThink = modelNewThink;// store it for further calculations.
}
}
Hope this helps.
P.S. In some way, suggested 'architecture' seems similar to MVP patter used in applications with user interface.

Categories