The is driving me nuts. Im trying to do a "simple" record insert and I can only get it to work if I store the context in a variable or create a local context. I tried to keep the context and model object tied together but no luck so far.
public class TransactionDataAccessLayer
{
public cartableContext transactionContext
{
get
{
return new cartableContext();
}
}
}
class TransactionBusinessLayer
{
Cardata newCar = new Cardata();
public void addCar(Cardata cd)
{
try
{
//this works. Storing the context in ctc2 seems to make it work???
TransactionDataAccessLayer tdal = new TransactionDataAccessLayer();
cartableContext ctc2 = tdal.transactionContext;
ctc2.cardata.Add(cd);
ctc2.SaveChanges();
//this does not work
tdal.transactionContext.cardata.Add(cd);
tdal.transactionContext.Entry(cd).State = EntityState.Modified;
tdal.transactionContext.SaveChanges();
}
catch (Exception ex)
{
Console.WriteLine(ex.InnerException);
}
}
}
In C#, properties are basically just fancy methods, designed to make it easier to access private fields. Therefore, returning a new Context in your getter will do just that; return a new one each time it is accessed. To preserve state, you need to contain your context in a private field, like so:
public class TransactionDataAccessLayer
{
private cartableContext _transactionContext;
public cartableContext transactionContext
{
get
{
if (_transactionContext == null)
_transactionContext = new cartableContext();
return _transactionContext;
}
}
}
Related
I have MVC application where I am trying to save some objects in session using DI framework of simple injector.
I register the objects as below
container.RegisterPerWebRequest<Func<HttpSessionState>>(() =>
() => HttpContext.Current.Session);
container.RegisterSingle<MemoryCache>(() => MemoryCache.Default);
container.RegisterPerWebRequest<ISessionCacheService, SessionCacheService>();
Now in the session service constructor I am able to see the multi-cast delegate for sessionstate object but when I try to add other objects I get the Object reference error. The constructor is listed below
protected internal Func<HttpSessionState> _HttpSessionState;
public SessionCacheService(Func<HttpSessionState> httpSessionState)
{
_HttpSessionState = httpSessionState;
}
I get the error in the following line of code inside a method of this service
public void Set<T>(string key, T data)
{
_HttpSessionState()[key] = data;
}
Here I can see that the following variable is null
this._HttpSessionState()
The main reason why we need to use this construct is that we need to store multicast delegate to session as shown in the example below
public RuntimeContext Current
{
get
{
Func<RuntimeContext> getRuntimeContextFunc = () =>
{
return new RuntimeContext()
{
ImpersonatingAgentId = Guid.Empty
};
};
return this._SessionCacheService.Get<RuntimeContext>(
typeof(RuntimeContext).ToString(),
getRuntimeContextFunc);
}
}
Later on we can retrieve these items from session using the get method
public T Get<T>(string key, Func<T> acquire)
{
if (this.IsSet(key))
{
return this.Get<T>(key);
}
else
{
var result = acquire();
this.Set<T>(key, result);
return result;
}
}
Below is the setup that I am trying to test.
The controller:
public ActionResult UpsertStudent(StudentModel studentModel)
{
try
{
if (!CheckStudentUpdateForEdit(studentModel))
{
return Json(new { result = STUDENT_EXISTS });
}
// remaining code removed for brevity
}
private bool CheckStudentUpdateForEdit(StudentModel studentModel)
{
var returnVal = true;
var existingStudent = _updateStudentManager.GetStudentInfo(studentModel.Id);
if (existingStudent.StudentType == "Day Scholar")
{
returnVal = true;
}
else
{
returnVal = false;
}
return returnVal;
}
The Test method:
public void AllowStudentUpdates_Success()
{
var studentModel = new StudentModel()
{
StudentName = "Joe",
Id = "123",
StudentType = "Day Scholar"
};
var studentToAdd = new Student()
{
Id = "123",
Name = "Joe",
StartDate = DateTime.UtcNow.ToShortDateString(),
StudentType = "Day Scholar",
EndDate = "08/10/2016"
};
_studentRulesHelper.Setup(x => x.GetStudentRule(studentModel, true)).Returns(studentToAdd);
_productRulesHelper.Setup(x => x.ReturnStudentRule(studentModel, true)).Returns(studentToAdd);
var res = _controller.UpsertStudent(studentModel) as JsonResult;
if (res != null) Assert.AreEqual("{ result = True }", res.Data.ToString());
}
When it hits the UpsertDoc call, it goes to the actual call in the controller and tries to execute CheckStudentUpdateForEdit() the GetStudentInfo() tries to get an object from the db and returns a null object as there is no student with the id that's passed from the test method.
The test then fails with Null Reference exception.
Now the system under test is not supposed to hit the db. I don't know why this is doing the other way!
Anyone else writing this test will also try to pass a dummy object which is bound to fail at GetStudentInfo() the way the test is setup now.
What do I do to make this work?
I am not sure if I have understood you problem correctly, but looking at the code snippets provided, the test will go and hit the database, because the mock object and its expectation is not defined.
I would have implemented the solution like this -
I am making some assumptions that your _updateStudentManager object is for the class that is doing the DB interaction for Student. I'll call it say StudentRepository. And to allow you to mock the behavior I would make it Interface driven.
So typically my setup would look like this -
//Interface
public interface IStudentrepository
{
StudentModel GetStudentInfo(int studentId);
}
//Class implementing IStudentrepository
public class StudentRepository : IStudentrepository
{
public StudentModel GetStudentInfo(int studentId)
{
//Implementation goes here
}
}
Now in my controller, I would have an instance of IStudentrepository, which can be injected via constructor.
public class StudentController
{
private readonly IStudentrepository updateStudentManager;
public StudentController(IStudentrepository updateStudentManager)
{
this.updateStudentManager = updateStudentManager;
}
}
//Rest of the code for controller....
Now while writing my Test, I will create a mock object of IStudentrepository, define the expectation for the mock object, and inject it when creating the controller object. Something like this.
[TestMethod]
public void TestMethod1()
{
//--Arrange--
//Define a mock object for student repository
var mock = new Mock<IStudentrepository>();
//Define the expectations of the mock object
mock.Setup(s => s.GetStudentInfo(It.IsAny<int>()))
.Returns(new StudentModel {/*return the required object */ });
//Instantiate controller and inject the mock object
StudentController _controller = new StudentController(mock.Object);
//--Act--
var res = _controller.UpsertStudent(studentModel) as JsonResult;
//--Assert--
if (res != null) Assert.AreEqual("{ result = True }", res.Data.ToString());
}
Now when your test method calls the GetStudentInfo method, instead of hitting the db, it will return the value as set in mock object.
This is just a high level implementation, and of course you can modify it as per your design. Hope it helps
I found this code here
using (var objCtx = new SchoolDBEntities())
{
var schoolCourse = from cs in objCtx.Courses
where cs.CourseName == "Course1"
select cs;
Course mathCourse = schoolCourse.FirstOrDefault<Course>();
IList<Course> courseList = schoolCourse.ToList<Course>();
string courseName = mathCourse.CourseName;
}
And I am using it in a Get method of a web api. When i use a using statement I get the following error
The ObjectContext instance has been disposed and can no longer be used for operations that require a connection
I I do not use it, then how would I dispose of the context object responsibly?
I use something like this to solve the problem without resorting to eager loading (in fact usually in a generic abstract base controller that I extend, but this example is simplified):
public class MyController : ApiController
{
private SchoolDBEntities _objCtx;
// Singleton ObjectContext
protected SchoolDBEntities objCtx
{
if(_objCtx == null) _objCtx = new SchoolDBEntities();
return _objCtx;
}
// Use singleton objCtx without using wrapper here, in Get() or other methods.
public String Get()
{
var schoolCourse = from cs in objCtx.Courses
where cs.CourseName == "Course1"
select cs;
Course mathCourse = schoolCourse.FirstOrDefault<Course>();
string courseName = mathCourse.CourseName;
return courseName
}
// ApiController implements IDisposable, so you can override Dispose to do clean-up here.
// This is not called until the controller is disposed, so you won't get the error you report.
protected override void Dispose(Boolean disposing)
{
if (_objCtx!= null)
{
_objCtx.Dispose();
_objCtx = null;
}
base.Dispose(disposing);
}
}
I am new to MongoDB, and am trying to get the C# driver to work serializing F# classes. I have it working with the class automapper using mutable F# fields & a parameterless constructor, but really I need to retain immutability, so I started looking at implementing an IBsonSerializer to perform custom serialization. I haven't found any documentation for writing one of these so have just tried to infer from the driver source code.
I have run into a problem whereby when the Deserialize method is called on the serializer, the CurrentBsonType is set to EndOfDocument rather than the start as I am expecting. I wrote the equivalent in C# just to make sure it wasn't some F# weirdness, but the problem persists. The serialization part seems to work fine and is queryable from the shell. Here is the sample code:
class Calendar {
public string Id { get; private set; }
public DateTime[] Holidays { get; private set; }
public Calendar(string id, DateTime[] holidays) {
Id = id;
Holidays = holidays;
}
}
class CalendarSerializer : BsonBaseSerializer {
public override void Serialize(BsonWriter bsonWriter, Type nominalType, object value, IBsonSerializationOptions options) {
var calendar = (Calendar) value;
bsonWriter.WriteStartDocument();
bsonWriter.WriteString("_id", calendar.Id);
bsonWriter.WriteName("holidays");
var ser = new ArraySerializer<DateTime>();
ser.Serialize(bsonWriter, typeof(DateTime[]), calendar.Holidays, null);
bsonWriter.WriteEndDocument();
}
public override object Deserialize(BsonReader bsonReader, Type nominalType, Type actualType, IBsonSerializationOptions options) {
if (nominalType != typeof(Calendar) || actualType != typeof(Calendar))
throw new BsonSerializationException();
if (bsonReader.CurrentBsonType != BsonType.Document)
throw new FileFormatException();
bsonReader.ReadStartDocument();
var id = bsonReader.ReadString("_id");
var ser = new ArraySerializer<DateTime>();
var holidays = (DateTime[])ser.Deserialize(bsonReader, typeof(DateTime[]), null);
bsonReader.ReadEndDocument();
return new Calendar(id, holidays);
}
public override bool GetDocumentId(object document, out object id, out Type idNominalType, out IIdGenerator idGenerator) {
var calendar = (Calendar) document;
id = calendar.Id;
idNominalType = typeof (string);
idGenerator = new StringObjectIdGenerator();
return true;
}
public override void SetDocumentId(object document, object id) {
throw new NotImplementedException("SetDocumentId is not implemented");
}
}
This blows up with FileFormatException in Deserialize when the CurrentBsonType is not Document. I am using the latest version 1.4 of the driver source.
I figured this out in the end. I should have used bsonReader.GetCurrentBsonType() instead of bsonReader.CurrentBsonType. This reads the BsonType in from the buffer rather than just looking at the last thing there. I also fixed a subsequent bug derserializing. The updated method looks like this:
public override object Deserialize(BsonReader bsonReader, Type nominalType, Type actualType, IBsonSerializationOptions options) {
if (nominalType != typeof(Calendar) || actualType != typeof(Calendar))
throw new BsonSerializationException();
if (bsonReader.GetCurrentBsonType() != BsonType.Document)
throw new FileFormatException();
bsonReader.ReadStartDocument();
var id = bsonReader.ReadString("_id");
bsonReader.ReadName();
var ser = new ArraySerializer<DateTime>();
var holidays = (DateTime[])ser.Deserialize(bsonReader, typeof(DateTime[]), null);
bsonReader.ReadEndDocument();
return new Calendar(id, holidays);
}
I have been scratching my head all morning behind this but still haven't been able to figure out what might be causing this.
I have a composite repository object that references two other repositories. I'm trying to instantiate a Model type in my LINQ query (see first code snippet).
public class SqlCommunityRepository : ICommunityRepository
{
private WebDataContext _ctx;
private IMarketRepository _marketRepository;
private IStateRepository _stateRepository;
public SqlCommunityRepository(WebDataContext ctx, IStateRepository stateRepository, IMarketRepository marketRepository)
{
_ctx = ctx;
_stateRepository = stateRepository;
_marketRepository = marketRepository;
}
public IQueryable<Model.Community> Communities
{
get
{
return (from comm in _ctx.Communities
select new Model.Community
{
CommunityId = comm.CommunityId,
CommunityName = comm.CommunityName,
City = comm.City,
PostalCode = comm.PostalCode,
Market = _marketRepository.GetMarket(comm.MarketId),
State = _stateRepository.GetState(comm.State)
}
);
}
}
}
The repository objects that I'm passing in look like this
public class SqlStateRepository : IStateRepository
{
private WebDataContext _ctx;
public SqlStateRepository(WebDataContext ctx)
{
_ctx = ctx;
}
public IQueryable<Model.State> States
{
get
{
return from state in _ctx.States
select new Model.State()
{
StateId = state.StateId,
StateName = state.StateName
};
}
}
public Model.State GetState(string stateName)
{
var s = (from state in States
where state.StateName.ToLower() == stateName
select state).FirstOrDefault();
return new Model.State()
{
StateId = s.StateId,
StateName = s.StateName
};
}
AND
public class SqlMarketRepository : IMarketRepository
{
private WebDataContext _ctx;
public SqlMarketRepository(WebDataContext ctx)
{
_ctx = ctx;
}
public IQueryable<Model.Market> Markets
{
get
{
return from market in _ctx.Markets
select new Model.Market()
{
MarketId = market.MarketId,
MarketName = market.MarketName,
StateId = market.StateId
};
}
}
public Model.Market GetMarket(int marketId)
{
return (from market in Markets
where market.MarketId == marketId
select market).FirstOrDefault();
}
}
This is how I'm wiring it all up:
WebDataContext ctx = new WebDataContext();
IMarketRepository mr = new SqlMarketRepository(ctx);
IStateRepository sr = new SqlStateRepository(ctx);
ICommunityRepository cr = new SqlCommunityRepository(ctx, sr, mr);
int commCount = cr.Communities.Count();
The last line in the above snippet is where it fails. When I debug through the instantiation (new Model.Community), it never goes into any of the other repository methods. I do not have a relationship between the underlying tables behind these three objects. Would this be the reason that LINQ to SQL is not able to build the expression tree right?
These are non-hydrated queries, not fully-hydrated collections.
The Communities query differs from the other two because it calls methods as objects are hydrated. These method calls are not translatable to SQL.
Normally this isn't a problem. For example: if you say Communities.ToList(), it will work and the methods will be called from the objects as they are hydrated.
If you modify the query such that the objects aren't hydrated, for example: when you say Communities.Count(), linq to sql attempts to send the method calls into the database and throws since it cannot. It does this even though those method calls ultimately would not affect the resulting count.
The simplest fix (if you truly expect fully hydrated collections) is to add ToList to the community query, hydrating it.
Try adding another repository method that looks like this:
public int CommunitiesCount()
{
get { return _ctx.Communities.Count(); }
}
This will allow you to return a count without exposing the entire object tree to the user, which is what I think you're trying to do anyway.
As you may have already guessed, I suspect that what you are calling the anonymous types are at fault (they're not really anonymous types; they are actual objects, which you are apparently partially populating in an effort to hide some of the fields from the end user).