Entity Framework saying invalid object name when table exists - c#

I've had to jump in to a complex project and am making unit tests for a particular repository in a WEB API service. The database CRUD is handled by the Entity Framework.
private class IntegrationScope : AutoRollbackTransactionTestScope<DocumentRepository>
{
public IntegrationScope()
{
DependencyResolverMock = MockDependencyResolverFor<IResourceUrlBuilder, ResourceUrlBuilder>(new ResourceUrlBuilder());
LoggingProviderMock = new Mock<ILoggingProvider>();
// use real document micro service AutoMapper & Unity configuration
AutoMapperConfig.RegisterMaps(Mapper.Configuration, DependencyResolverMock);
UnityConfig.RegisterTypes(TestScopeContainer);
//Set the DomainId
TestId = Guid.NewGuid();
TestDocument = BuildDocument(TestId);
// get the real object
DocumentStoreDbContext = TestScopeContainer.Resolve<IDocumentDbContext>();
InstanceUnderTest = new DocumentRepository(DocumentStoreDbContext);
}
public static Web.Service.DocumentStore.Domain.Document BuildDocument(Guid documentId)
{
// Invoke GetBytes method.
byte[] array = Encoding.ASCII.GetBytes("Byte Repository Test");
return Builder<Web.Service.DocumentStore.Domain.Document>
.CreateNew()
.With(t => t.Id = documentId)
.With(t => t.Data = array)
.Build();
}
When it gets to the DocumentStoreDbContext line, there is no compilation error but i get a run-time error saying that the object name is invalid:
After doing some research this error appears to be because the database/table doesn't exist, however I can see that it does exist:
What am I doing wrong and how do I fix it?

InnerException displays the table name as DocumentStore.Documents, but your SSMS screenshot shows dbo.Documents.
Could this be the cause?

Related

AutoMapper exception When converting one DTO to another object

I am trying to run a test to check that my mapping is correct however every time I run the debugger I get an AutoMapperMappingException.
My code:
public BB.LMS.Models.CaseExport ConvertStarsCaseExportToCaseExport(BB.LMS.Services.Core.Models.Stars.caseexport caseExport)
{
Mapper.CreateMap<BB.LMS.Services.Core.Models.Stars.caseexport, CaseExport>();
var ConvertedCase = Mapper.Map<BB.LMS.Services.Core.Models.Stars.caseexport, BB.LMS.Models.CaseExport>(caseExport);
return ConvertedCase;
}
and
[TestMethod()]
public void ConvertToCaseTest()
{
DTOService service = new DTOService();
caseexport export = xmlService.DeserializeStarsExport(testStarsFile);
CaseExport convertedCase = service.ConvertStarsCaseExportToCaseExport(export);
Exception:
{
"Missing type map configuration or unsupported mapping.\r\n\r\nMapping types:\r\ncase -> Case\r\nBB.LMS.Services.Core.Models.Stars.case -> BB.LMS.Models.Case\r\n\r\nDestination path:\r\nCaseExport.solicitor.solicitor.case.case\r\n\r\nSource value:\r\nBB.LMS.Services.Core.Models.Stars.case"
}
FIXED: As Sergey L correctly pointed out, I hadn't mapped case -> Case once that had been mapped my code worked a treat!
The error says automapper needs configuration in order to be able to map.
Here is one way to do it :
public BB.LMS.Models.CaseExport ConvertStarsCaseExportToCaseExport(BB.LMS.Services.Core.Models.Stars.caseexport caseExport)
{
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<BB.LMS.Services.Core.Models.Stars.caseexport, CaseExport>();
});
var mapper = config.CreateMapper();
var ConvertedCase = mapper.Map<BB.LMS.Services.Core.Models.Stars.caseexport, BB.LMS.Models.CaseExport>(caseExport);
return ConvertedCase;
}

Is it possible to retrieve a MetadataWorkspace without having a connection to a database?

I am writing a test library that needs to traverse the Entity Framework MetadataWorkspace for a given DbContext type. However, as this is a test library I would rather not have a connection to the database - it introduces dependencies that may not be available from the test environment.
When I try to get a reference to the MetadataWorkspace like so:
var metadata = ((IObjectContextAdapter)context).ObjectContext.MetadataWorkspace;
I get a SqlException:
An exception of type 'System.Data.SqlClient.SqlException' occurred in System.Data.dll but was not handled in user code
Additional information: A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 26 - Error Locating Server/Instance Specified)
Is it possible to do what I want without a connection string?
Yes you can do this by feeding context a dummy connection string. Note that usually when you call parameterless constructor of DbContext, it will look for connection string with the name of your context class in app.config file of main application. If that is the case and you cannot change this behavior (like you don't own the source code of context in question) - you will have to update app.config with that dummy conneciton string (can be done in runtime too). If you can call DbContext constructor with connection string, then:
var cs = String.Format("metadata=res://*/{0}.csdl|res://*/{0}.ssdl|res://*/{0}.msl;provider=System.Data.SqlClient;provider connection string=\"\"", "TestModel");
using (var ctx = new TestDBEntities(cs)) {
var metadata = ((IObjectContextAdapter)ctx).ObjectContext.MetadataWorkspace;
// no throw here
Console.WriteLine(metadata);
}
So you providing only parameters important to obtain metadata workspace, and providing empty connection string.
UPDATE: after more thought, you don't need to use such hacks and instantiate context at all.
public static MetadataWorkspace GetMetadataWorkspaceOf<T>(string modelName) where T:DbContext {
return new MetadataWorkspace(new[] { $"res://*/{modelName}.csdl", $"res://*/{modelName}.ssdl", $"res://*/{modelName}.msl" }, new[] {typeof(T).Assembly});
}
Here you just use constructor of MetadataWorkspace class directly, passing it paths to target metadata elements and also assembly to inspect. Note that this method makes some assumptions: that metadata artifacts are embedded into resources (usually they are, but can be external, or embedded under another paths) and that everything needed is in the same assembly as Context class itself (you might in theory have context in one assembly and entity classes in another, or something). But I hope you get the idea.
UPDATE2: to get metadata workspace of code-first model is somewhat more complicated, because edmx file for that model is generated at runtime. Where and how it is generated is implementation detail. However, you can still get metadata workspace with some efforts:
public static MetadataWorkspace GetMetadataWorkspaceOfCodeFirst<T>() where T : DbContext {
// require constructor which accepts connection string
var constructor = typeof (T).GetConstructor(new[] {typeof (string)});
if (constructor == null)
throw new Exception("Constructor with one string argument is required.");
// pass dummy connection string to it. You cannot pass empty one, so use some parameters there
var ctx = (DbContext) constructor.Invoke(new object[] {"App=EntityFramework"});
try {
var ms = new MemoryStream();
var writer = new XmlTextWriter(ms, Encoding.UTF8);
// here is first catch - generate edmx file yourself and save to xml document
EdmxWriter.WriteEdmx(ctx, writer);
ms.Seek(0, SeekOrigin.Begin);
var rawEdmx = XDocument.Load(ms);
// now we are crude-parsing edmx to get to the elements we need
var runtime = rawEdmx.Root.Elements().First(c => c.Name.LocalName == "Runtime");
var cModel = runtime.Elements().First(c => c.Name.LocalName == "ConceptualModels").Elements().First();
var sModel = runtime.Elements().First(c => c.Name.LocalName == "StorageModels").Elements().First();
var mModel = runtime.Elements().First(c => c.Name.LocalName == "Mappings").Elements().First();
// now we build a list of stuff needed for constructor of MetadataWorkspace
var cItems = new EdmItemCollection(new[] {XmlReader.Create(new StringReader(cModel.ToString()))});
var sItems = new StoreItemCollection(new[] {XmlReader.Create(new StringReader(sModel.ToString()))});
var mItems = new StorageMappingItemCollection(cItems, sItems, new[] {XmlReader.Create(new StringReader(mModel.ToString()))});
// and done
return new MetadataWorkspace(() => cItems, () => sItems, () => mItems);
}
finally {
ctx.Dispose();
}
}
The solution proposed by Evk did not work for me as EdmxWriter.WriteEdmx would eventually connect to the database.
Here is how I solved this:
var dbContextType = typeof(MyDbContext);
var dbContextInfo = new DbContextInfo(dbContextType, new DbProviderInfo(providerInvariantName: "System.Data.SqlClient", providerManifestToken: "2008"));
using (var context = dbContextInfo.CreateInstance() ?? throw new Exception($"Failed to create an instance of {dbContextType}. Does it have a default constructor?"))
{
var workspace = ((IObjectContextAdapter)context).ObjectContext.MetadataWorkspace;
// ... use the workspace ...
}
By creating the context this way, Entity Framework does not try to connect to the database when accessing the ObjectContext property.
Note that your DbContext class must have a default constructor for this solution to work.

MVC4 Unit test NSubstitute Could not find a call to return from

I have a MVC4 web application I'm unit testing right now. It uses entity framework for the database portion. I'm using NSubstitute to mock the database. This code is basically copied and pasted from another site which works fine, so I hope I'm just missing something super simple.
Thanks in advance!
Applications table in SQL:
AppID | ApplicationName
----------------------------
1 | MyCoolApplication
2 | MyOtherApplication
Entity created the Application class:
public class Application
{
public int AppID { get; set; }
public string ApplicationName { get; set; }
}
The mock section of the unit test looks like this:
var mockDb = Substitute.For<MyCoolApplicationsEntities>();
var applications = new List<Application>
{
new Application {AppID = 1, ApplicationName = "MyCoolApplication"},
new Application {AppID = 2, ApplicationName = "MyOtherApplication"},
};
var mockApplicationSet = Substitute.For<IDbSet<Application>, DbSet<Application>>();
mockApplicationSet.Provider.Returns(applications.AsQueryable().Provider);
mockApplicationSet.Expression.Returns(applications.AsQueryable().Expression);
mockApplicationSet.ElementType.Returns(applications.AsQueryable().ElementType);
mockApplicationSet.GetEnumerator().Returns(applications.AsQueryable().GetEnumerator());
mockApplicationSet.When(q => q.Add(Arg.Any<Application>()))
.Do(q => applications.Add(q.Arg<Application>()));
mockApplicationSet.When(q => q.Remove(Arg.Any<Application>()))
.Do(q => applications.Remove(q.Arg<Application>()));
mockDb.Applications.Returns(mockApplicationSet); //This is the line creating the error
The full error is:
Test method
MyProjectName.Controllers.MyControllerTest.TestOfSectionImTesting
threw exception:
NSubstitute.Exceptions.CouldNotSetReturnDueToNoLastCallException:
Could not find a call to return from.
Make sure you called Returns() after calling your substitute (for
example: mySub.SomeMethod().Returns(value)), and that you are not
configuring other substitutes within Returns() (for example, avoid
this: mySub.SomeMethod().Returns(ConfigOtherSub())).
If you substituted for a class rather than an interface, check that
the call to your substitute was on a virtual/abstract member. Return
values cannot be configured for non-virtual/non-abstract members.
Correct use:
mySub.SomeMethod().Returns(returnValue);
Potentially problematic use:
mySub.SomeMethod().Returns(ConfigOtherSub());
Instead try:
var returnValue = ConfigOtherSub();
mySub.SomeMethod().Returns(returnValue);
But that doesn't work in my environment because Applications isn't a method. Like I said, this works fine in another site of mine, so it's got to be something basic I'm missing. Nothing I've found online has been helpful with my particular case. I updated to the newest version of NSubstitute and I uninstalled/reinstalled, but still have got nothing.
Again, thanks in advance!
NSubstitute can not mock non-virtual members. (There are quite a few caveats to substituting for classes.)
MyCoolApplicationsEntities.Applications will need to be virtual for .Returns() to work.
Here's what ended up working:
var context = Substitute.For<MyCoolApplicationsEntities>();
var applications = new List<Application>
{
new Application {AppID = 1, ApplicationName = "MyCoolApplication"}
};
var mockApplications = Substitute.For<DbSet<Application>, IQueryable<Application>>();
((IQueryable<Application>)mockApplications).Provider.Returns(applications.AsQueryable().Provider);
((IQueryable<Application>)mockApplications).Expression.Returns(applications.AsQueryable().Expression);
((IQueryable<Application>)mockApplications).ElementType.Returns(applications.AsQueryable().ElementType);
((IQueryable<Application>)mockApplications).GetEnumerator().Returns(applications.AsQueryable().GetEnumerator());
mockApplications.When(q => q.Add(Arg.Any<Application>()))
.Do(q => applications.Add(q.Arg<Application>()));
mockApplications.When(q => q.Remove(Arg.Any<Application>()))
.Do(q => applications.Remove(q.Arg<Application>()));
context.Applications = mockApplications;
I can't see you classes but you need to create interfaces with virtual members and have your code call the class by the interface, then you will be able to mock out the class.

Update detached objects in EF that already exist in object state manager

I'm hoping this will be an easy one but for the life of me, I cannot find the specific answer elsewhere on SO or any other site.
I have a basic repository/unit of work pattern with Entity Framework Code First. It all works smoothly except for certain cases of Update. THe problem is I have a set of Entity Framework model objects, all prefixed with "Db" which EF returns, but I then convert them to plain DataContract Model objects to pass to the Web layer to give separation of concerns. I have a basic conversion interface that just populates a WebModel object from the DataModel object, copying field by field verbatim.
So if you retrieve a DbUser object from EF with ID of 1, then convert to a User object, then convert that BACK to a DbUser object, you end up with a DbUser with ID of 1, but it is a DIFFERENT object to the one you started with, though they have the same primary key field, the actual CLR objects themselves are different.
The following works
User user;
using (var work = new UnitOfWork())
{
var repository = new UserDataRepository(work);
user = repository.Get(1);
repository.save();
}
var modelUser = DataConverter.Convert(user);
modelUser.Name = "new name";
user = BusinessConverter.Convert(modelUser);
using (var work = new UnitOfWork())
{
var repository = new UserDataRepository(work);
repository.Update(user);
repository.save();
}
As they are using two different unit of works/contexts, so the second block has nothing in the ObjectStateManager to compare to and can just attach the detached object in the Update() methods
This, however does NOT work
using (var work = new UnitOfWork())
{
var repository = new UserDataRepository(work);
user = repository.Get(1);
repository.save();
var modelUser = DataConverter.Convert(user);
modelUser.Name = "new name";
user = BusinessConverter.Convert(modelUser)
repository.Update(user);
repository.save();
}
NOTE: I know logically this doesn't make much sense to convert and just convert back but go with it, I've simplified the example greatly to make it easier to put into paper, in my actual code there is a reason for doing it that way.
I get the usual error "an object with the same key already exists in the objectstatemanager...". I'm assuming because the Get() loads the object into EF and then the update sees that the object is detached, then tries to attach it and it already exists.
My Update method in my repository is as below
public override bool UpdateItem(DbUser item)
{
if (Work.Context.Entry(item).State == EntityState.Detached)
Work.Context.Users.Attach(item);
Work.Context.Entry(item).State = EntityState.Modified;
return Work.Context.Entry(item).GetValidationResult().IsValid;
}
I made this Extension method to the DbContext to ReAttach the Entity without problems try it out:
public static void ReAttach<T>(this DbContext context, T entity) where T : class
{
var objContext = ((IObjectContextAdapter) context).ObjectContext;
var objSet = objContext.CreateObjectSet<T>();
var entityKey = objContext.CreateEntityKey(objSet.EntitySet.Name, entity);
Object foundEntity;
var exists = objContext.TryGetObjectByKey(entityKey, out foundEntity);
// Detach it here to prevent side-effects
if (exists)
{
objContext.Detach(foundEntity);
}
context.Set<T>().Attach(entity);
}
Then just update your method :
public override bool UpdateItem(DbUser item)
{
Work.Context.ReAttach(item);
Work.Context.Entry(item).State = EntityState.Modified;
return Work.Context.Entry(item).GetValidationResult().IsValid;
}
You might get a manged Entity, and again verbatim map the new DbUser's properties to the managed Object:
public override bool UpdateItem(DbUser item)
{
using (var work = new UnitOfWork())
{
var repository = new UserDataRepository(work);
DbUser managedUser = repository.Get(item.PK);
//foreach DbUser property map the item to managedUser
managedUser.field1 = item.field1;
[..]
repository.Update(managedUser);
repository.Save();
}
}
If you set your context to AsNoTracking() this will stop aspmvc tracking the changes to the entity in memory (which is what you want anyway on the web).
_dbContext.Products.AsNoTracking().Find(id);
I would recommend you read more about this at http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/advanced-entity-framework-scenarios-for-an-mvc-web-application
Yash

CRM error while trying to deserialize parameter

I have a CRM function that returns the attribute types of all attributes in a entity. My problem is all though this same method has worked in the past it's now throwing this error regardless of the entity I pass in to it.
There was an error while trying to deserialize parameter http://schemas.microsoft.com/xrm/2011/Contracts/Services:ExecuteResult
Here is my code, I'm passing in the "account" entity.
public string GetFieldType(IOrganizationService svc, string entity, string fieldName)
{
RetrieveEntityRequest request = new RetrieveEntityRequest()
{
EntityFilters = EntityFilters.Attributes,
LogicalName = entity
};
RetrieveEntityResponse response = (RetrieveEntityResponse)svc.Execute(request);
string type = "";
foreach (AttributeMetadata attribute in response.EntityMetadata.Attributes)
{
if (attribute.LogicalName == fieldName)
{ type = attribute.AttributeType.ToString(); }
}
return type;
}
If the code was working before, and it's not now, odds are that it is not a problem with your code. Most likely your svc.Execute is failing. Have you changed how your IOrganizationService is being created? Are you running as a user with rights to query the CRM instance? If all of these things check out, then try turning on server side tracing through the diagnostic tool.

Categories

Resources