I have a C# EF 6 Database First project("DocRetData") that I am using as my "Model" in a VB.Net Web Forms project. I'm also using the "Web Forms Scafolding" extension. I have added a reference to the EF project and then created "New Scaffold Item". Project compiles. When I run it and access the "Default" page it lists items just fine, but when I go to Edit or Create a new item I get System.ArgumentNullException in the GetData() function of ForeignKey_EditField Class. It looks like this:
Public Function GetData() As IQueryable
Dim entityType = Type.[GetType](Me.DataTypeName)
Return _db.[Set](entityType).AsQueryable()
End Function
This has to be something do with a reference conflict of some kind, because if I remove Data Project, add the Model as a class within the Web Forms project and go through all the same steps then I don't get the error and can Edit or Create items just fine.
The data structure here is a fairly simple one. The Table(Object) I'm trying to reference here is has the following structure:
[AppSettingID] [int] IDENTITY(1,1) NOT NULL,
[CountyID] [int] NOT NULL,
[Name] [varchar](30) NOT NULL,
[VariableName] [varchar](50) NOT NULL,
[Setting] [varchar](4000) NOT NULL,
[FieldDataTypeID] [int] NOT NULL,
where CountyID and FieldDataTypeID are foreign keys to other tables.
The Error occurs on the Return statement because the entityType is null. The Me.DataTypeName is "DocRetData.County". I'm guessing this has something to do with the way that VB.Net does/does not handle Namespaces but have not been able to track it down.
Thanks
dbl
Im not sure how it would apply to VB but in C# this is the change you need to make if the Type exists in a different class library
public IQueryable GetData()
{
var entityType = Type.GetType(this.DataTypeName + ",DAL");
return _db.Set(entityType).AsQueryable();
}
So in my example my Class Library where my Entities exists is Called DAL. My DataTypeName was "DAL.tbl_Jobs"
So Type.GetType("DAL.tbl_Jobs,DAL") return the Entity Type.
Hope this helps
Related
I have used breeze's CreateEntity a few times when table's PK is a user-entered value. And a few times with SQL SERVER when PK is an IDENTITY. This is my first time trying to do it when PK is autogenerated ID (actually a "sequence") in ORACLE. It isn't working.
I do check first to make sure I have fetched the Metadata then create the new, empty entity that will be filled in with values by user.
My code to createEntity (newEntity is a knockout Observable):
function createEntity(newEntity) {
newEntity(manager.createEntity(entityNames.escctransactions, {})); <<<<< this fails
return;
}
The Error:
Cannot attach an object of type (ESCC_TRANSACTIONS:... ) to an EntityManager without first setting its key or setting its entityType 'AutoGeneratedKeyType' property to something other than 'None'
I know I need to set the AutoGeneratedKeyType to "Identity" but not sure how to do it. Tried this when I'm inititalizing the metadata, but still getting same error so it's obviously not working:
var entyType = manager.metadataStore.getEntityType("ESCC_TRANSACTIONS");
entyType.setProperties({ AutoGeneratedKeyType: AutoGeneratedKeyType.Identity });
I've seen something about doing it in a constructor but I've never used a constructor in JavaScript. Also something about changing it in a config?
Using Breeze 1.6, Knockout.js 3.4, .NET 4.5.2 framework
THANKS
Figured it out myself and it's working now. The code to set AutoGeneratedKeyType is as follows:
var entityType = manager.metadataStore.getEntityType("ESCC_TRANSACTIONS");
entityType.autoGeneratedKeyType = "Identity";
Or this works:
var entityType = manager.metadataStore.getEntityType("ESCC_TRANSACTIONS");
entityType.autoGeneratedKeyType = breeze.AutoGeneratedKeyType.Identity;
And in spite of the Breeze documentation for AutoGeneratedKeyType here:
http://breeze.github.io/doc-js/api-docs/classes/AutoGeneratedKeyType.html, it's not a capital "A" in Auto, it's a small "a".
I've seen in OData documentation that there are Edm types Date and Time. Currently in my database there are many DATE fields being represented in EF as DateTimes, so the ODataConventionModelBuilder is declaring them as Edm.DateTime. How can I change them to Edm.Date?
Was hoping I could do this:
entityType.Property(p => p.AgreementDate).EdmType = EdmType.Date;
The corresponding Edm type of certain property is mapped from the CLR type and can't be overrided by ODataConventionModelBuilder.
If you want to change the Edm type, you can ignore these properties within the ODataConventionModelBuilder.
After getting the Edm model by calling GetEdmModel on the ODataConventionModelBuilder, you can add these properties with Edm.Date to the Edm model by calling OData APIs.
Here's my answer in case someone is interested in the details of how to implement Feng Zhao's suggestion. I didn't find the API too discoverable, so I wanted to share.
First, build your EDM model as usual with the ODataConventionModelBuilder but ignore the date property:
...
entitType.Ignore(p => p.AgreementDate);
...
IEdmModel model = builder.GetEdmModel();
Then add the date property "manually":
var myType = (EdmStructuredType)model.FindDeclaredType(typeof(MyType).FullName);
var dateType = (IEdmPrimitiveType)model.FindType("Edm.Date");
myType.AddProperty(new EdmStructuralProperty(myType, "AgreementDate", new EdmPrimitiveTypeReference(dateType, false)));
That's it.
I've managed to create number of readonly Web Api OData services following the tutorials here: http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api. I'm therefore employing the ODataConventionModel builder to create the model from a set of entities (incidentally coming from a Telerik ORM). This all seems to work fine and I can happily issue queries, view the metadata and so forth on the service.
I've now tried to turn my attention to the other CRUD operations - firstly Create and have stumbled into a problem! Namely, the Post method fires correctly (CreateEntity) but the entity parameter is null - by doing a check against the ModelState.IsValid, it shows that the problem is a null ID (key) value. This is unsurprising because the database uses a Database Generated Identity for the ID column and therefore the ID would be created when the entity is saved into the database context.
I've therefore tried all sorts of ways of marking the ID column as database generated, but haven't managed to find anything. Strangely, I can't seem to find even one post of someone asking for this - surely I can't be the only one?!
I noted that when looking at the EF modelbuilder (for example here: http://forums.asp.net/t/1848984.aspx/1) there appears to be a means of affecting the model builder with a .HasDatabaseGeneratedOption property, but no similar option exists in the System.Web.Http.OData equivalent.
So the questions therefore are:
Is there a means of altering the model builder (or something else) so that the controller will accept the object and deserialize the entity even with a null key value?
If so, how can I do this?
If not, any suggestions as to other options?
I realise that I could potentially just populate the object with an (in this case) integer value from the client request, but this seems a) semantically wrong and b) won't necessarilly always be possible as a result of the client toolkit that might be used.
All help gratefully received!
Many thanks,
J.
You need to create a viewmodel for insert which does not contain the ID parameter. Use Automapper to map the properties of the incoming insert-model to your data entities.
The problem that you're having is that ID is a required attribute in your data model because it is your PK, except during insert, where it shouldn't be specified.
In my case, my database-generated key is a Guid.
As a work-around, in my TypeScript client code, I submit (via http POST) the object with an empty Guid like this: Note: ErrorId is the key column.
let elmahEntry: ELMAH_Error = {
Application: 'PTUnconvCost',
Host: this.serviceConfig.url,
Message: message,
User: that.userService.currentUserEmail,
AllXml: `<info><![CDATA[\r\n\r\n${JSON.stringify(info || {})}\r\n\r\n]]></info>`,
Sequence: 1,
Source: source,
StatusCode: 0,
TimeUtc: new Date(Date.now()),
Type: '',
ErrorId: '00000000-0000-0000-0000-000000000000'
};
Then, in my WebApi OData controller, I check to see if the key is the empty guid, and if so, I replace it with a new Guid, like this:
// POST: odata/ELMAH_Error
public IHttpActionResult Post(ELMAH_Error eLMAH_Error)
{
if (eLMAH_Error.ErrorId == Guid.Empty)
{
eLMAH_Error.ErrorId = Guid.NewGuid();
}
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.ELMAH_Error.Add(eLMAH_Error);
try
{
db.SaveChanges();
}
catch (DbUpdateException)
{
if (ELMAH_ErrorExists(eLMAH_Error.ErrorId))
{
return Conflict();
}
else
{
throw;
}
}
return Created(eLMAH_Error);
}
Using MVC 3 with Razor view engine.
I have this View:
#model dynamic
#{
var products = (List<ListItemBaseModel>)Model.Products;
var threshold = (int)(Model.Threshold ?? 1);
var id = Guid.NewGuid().ToString();
}
It is called from another view using this code:
#Html.Partial("PartialViewName", new { Products = Model, Threshold = 5 })
In both Views, when I debug them and watch Model, it seems to contain the correct object.
When I execute the code I get an error on the var products = line saying:
'object' does not contain a definition for 'Products'
Why do I see this error?
When I watch the Model object in debugging mode it looks all right (having 2 properties: Products and Threshold)
I just tried this (dynamic view model in CSHTML) and got the same error as your when using an anonymous class, but it worked fine if I created a named class. I searched but haven't seen this documented anywhere.
// error
return View(new { Foo = 1, Bar = "test" });
// worked
return View(new TestClass { Foo = 1, Bar = "test" });
David Ebbo clarified that you can't pass an anonymous type into a dynamically-typed view because the anonymous types are compiled as internal. Since the CSHTML view is compiled into a separate assembly, it can't access the anonymous type's properties. Due to this forum post, David Ebbo clarified on (Dec 22 2011) that MVC 3 now has direct support for dynamic.
On .NET 4.0 Anonymous types can easily be converted to ExpandoObjects and thus all the problems are fixed with the overhead of the conversion itself.
Check out here
This has nothing to do with anonymous types having internal properties
It is perfectly possible to pass anonymous types from a view to a partial view
I encountered the same problem today and it was nothing (directly) to do with the problem of passing anonymous types and their inherent internal properties.
As such, in relation to the OPs question, the answer by #Lucas is irrelevant - even though the workaround will work.
In the OPs question, an anonymous type is being passed from a view in assembly X to a partial in assembly X, therefore the problem that David Ebbo outlined of the properties being internal for anonymous types is of no consequence; the types compiled for the view, the partial and the anonymous type are all contained in the same assembly.
So what is causing the sudden failure to pass an anonymous type from a view to a partial?
At least in my situation, I discovered that it was due to having another view in the SAME FOLDER that specifies a model type that cannot be resolved. Views get compiled at runtime, and so it would make sense as a failure at runtime to compile the views would also mean a failure to compile the dynamic types and the partial would simply receive an object. It's not immediately obvious what is going on, but in the OPs specific example (and mine) this is more than likely the cause of the problem.
It is interesting to note that if the model type is correct but another part of the view doesn't compile then anonymous types are not affected in the same way. This must be down to how Razor breaks up the dynamic compilation of the component parts of the view.
Once you correct the offending view, either rebuild the whole solution or clean and rebuild the project before checking to see if it's fixed.
To ensure you are not caught out by this again you can enable compile time compilation of your Razor views by adding this to your csproj file:
<PropertyGroup>
<MvcBuildViews>true</MvcBuildViews>
</PropertyGroup>
Add the following class anywhere in your solution (use System namespace, so its ready to use without having to add any references) -
namespace System
{
public static class ExpandoHelper
{
public static ExpandoObject ToExpando(this object anonymousObject)
{
IDictionary<string, object> anonymousDictionary = HtmlHelper.AnonymousObjectToHtmlAttributes(anonymousObject);
IDictionary<string, object> expando = new ExpandoObject();
foreach (var item in anonymousDictionary)
expando.Add(item);
return (ExpandoObject)expando;
}
}
}
When you send the model to the view, convert it to Expando :
return View(new {x=4, y=6}.ToExpando());
Instead of using the dynamic Model type within the partial view.
You can call the anonymous object attributes using #ViewData.Eval("foo") instead of #Model.foo.
Then you can remove #Model dynamic from the view.
I came across this issue recently when passing some attributes between views for the Facebook Social Comments Integration. Example code:
Html.RenderPartial(#"Layouts/Partials/_Comments", new {currentUrl = Model.CurrentPage.GetAbsoluteUrl(), commentCount = 5 });
Then in my view I just had this div:
<div class="fb-comments" data-href="#ViewData.Eval("currentUrl")" data-numposts="#ViewData.Eval("commentCount")" data-width="100%"></div>
i am not sure that you are getting this error because you are not implementing the work-around. i got the same error in a partial view. the solution was just to clean the build and rebuild it. if the syntax is correct, the code should work, but the razor engine may not be updating the code changes properly.
I worked around this issue by using a Dictionary.
#Html.Partial("_Partial", new Dictionary<string, string> { { "Key1", "Val1" }, { "Key2", "Val2" }, { "Key3", "Val3" } });
To use dynamic type you need to reference Microsoft.CSharp assembly
I tried to use SubSunsonic.ActiveRecord in SL3 project that uses .NET RIA Services.
However when I try to return some IQuerable in DomainService class I get an error that the classes generated by Subsonic have a property 'Columns' with an unsupported type.
That's what I have
public IEnumerable<SE_NorthWind.SuperEmployee> GetIntegers()
{
return SE_NorthWind.SuperEmployee.All()
.Where(emp => emp.Issues > 100)
.OrderBy(emp => emp.EmployeeID);
}
And this is the error I get
Error 7 Entity 'SE_NorthWind.SuperEmployee' has a property 'Columns' with an unsupported type. SuperEmployee
Any idea what to do? Don't really wanna use Linq to SQL :)
Thx
P.S. Just tried to LinqTemplates from SubSonic, but this solution I get the error
Error 4 The entity 'SE_NorthWind.SuperEmployee' does not have a key defined. Entities exposed by DomainService operations must have must have at least one property marked with the KeyAttribute. SuperEmployee
of course SuperEmployee table has a primary key, cause the classes generated by SubSonic can see it
...
Columns.Add(new DatabaseColumn("EmployeeID", this)
{
IsPrimaryKey = true,
DataType = DbType.Int32,
IsNullable = false,
AutoIncrement = true,
IsForeignKey = false,
MaxLength = 0
});
...
But RIA objects, they need some attributes. I guess I'll have to go with native Linq To SQL until SubSonic adapts to all this :(
To answer the second part of your question.
You need to add the "KeyAttribute" to the PrimaryKey property on the "EmployeeId" property.
The attribute is in the "System.ComponentModel.DataAnnotations" namespace.
No up on Sub Sonic 3, but you could change the underlying template to generate this, or change the sub sonic engine and submit it as a patch.
I'm running with SilverLight 3 with RaiServices.
Hope this helps.
Can you try removing the [EnableClientAccess()] attribute to see if your project will build?