the problem im having is related to the datareader being incompatible to the model I specified, i thought that by adding the Column name it would work, but it doesnt. Here is the code related to the problem at hand.
Model:
[Table("IPs")]
public class Ip : BaseEntity
{
[Key]
public int Id { get; set; }
[Column("IdItem")]
public int? ItemId { get; set; }
[Column("EnUso")]
public string En_Uso { get; set; }
//more properties...
}
The method that is failing works with generics, the ModelClass would be Ip here:
var table = TableName<ModelClass>();
var primaryKey = PrimaryKeyProperty<ModelClass>().Name; //this one uses reflection to see which one get the Key
var query = String.Format(FindQuery(), table, primaryKey, id);
// The resulting query is this for example: Select * from IPs WHERE id = 1
var result = DBSet().SqlQuery(query); //here it fails
return result.FirstOrDefault();
The error im getting:
the data reader is incompatible with the specified
'Inventario.Models.Ip'. A member of the type, 'ItemId', does not have
a corresponding column in the data reader with the same name.
If i change the column name to IdItem, then it breaks on "En_Uso", while changing some of the properties wouldnt be a problem
I would like to fix it if possible in a way with data annotations or something of the sort that doesnt requiere to use the exact table names, but I already specified the column name i dont know what else.
to do
Related
I've tried this code shown below in another project and it works, so problem is surely not in a method responsible for getting data from database by ID. Unfortunately, I wasn't able figure out what causes the problem.
Simplest test case: I initialize MongoDB class with methods to work with database. Then I load every record stored in database using method LoadRecords() to collection.
// some code
MongoDB db = new MongoDB("People");
List<Person> collection = db.LoadRecords<Person>("Person");
//some code
public List<T> LoadRecords<T>(string table)
{
var collection = db.GetCollection<T>(table);
return collection.Find(new BsonDocument()).ToList();
}
That works fine, it gives me collection of every document in table. Now I try to find only one element with, for example, ID of first element from that collection using method LoadRecordById().
// some code
Person oneRecord = db.LoadRecordById<Person>("Person", people[0].Id);
// some code
public T LoadRecordById<T>(string table, Guid id)
{
var collection = db.GetCollection<T>(table);
var filter = Builders<T>.Filter.Eq("ID", id);
return collection.Find(filter).First();
}
My Person class is also very simple, only includes a few properties and ID:
[BsonIgnoreExtraElements]
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
[BsonId]
public Guid Id { get; set; }
}
It really makes no sense to me, first it gives me every record stored in database (its FirstName, LastName, ID) and then when I want to search one record with the exactly same ID it gave me before, it crashes.
Result is an unhandled exception of type 'System.InvalidOperationException' occurred in System.Core.dll
Additional information: Sequence contains no elements
I have a database that I can't change. One of its tables' column names is MFG-DATE (with a hyphen). I made a class for the table:
public class tblPreNeltec
{
[Key]
public string LotNo { get; set; }
//...
[Column("MFG-DATE")]
public DateTime? MFG_DATE {get; set; }
}
So I would think when I try to get tblPreNeltecs out of the database, it should work, right? yet when I run
var lots = db.tblPreNeltecSet.SqlQuery("SELECT * FROM tblPreNeltec WHERE LotNo LIKE #LotNo", new SqlParameter("#LotNo", LotNo)).ToList();
I get an error:
The data reader is incompatible with the specified 'CofC.Models.tblPreNeltec'. A member of the type, 'MFG_DATE', does not have a corresponding column in the data reader with the same name.
But it shouldn't be MFG_DATE! I used the Column attribute, it should be looking for MFG-DATE! Right? what am I doing wrong? And for that matter, how can I retrieve a bunch of tblPreNeltecs from the database by lot number, given that they have a column which has a hyphen in its name?
I'm trying to create a generic Add that will return the actual values from the DB, because some of the values might be calculated by SQL.
For example:
public partial class Customer
{
public string ClientNum { get; set; }
public string ClientName { get; set; }
public string CompanyName { get; set; }
public string Adress { get; set; }
public System.Guid SysRowID { get; set; }
}
SysRowId is calulated at SQL as newid(). So, after inserting the new record I want to do a Find. How may I do that in a generic way?
So far I have this:
var newDBRow = CreateDBRow(tableIndex);
FillValues(newDBRow);
Db.Set(newDBRow.GetType()).Add(newDBRow);
Db.SaveChanges();
var entry = Db.Entry(newDBRow); //SysRowID is blank at CurrentValues
newDBRow = Db.Set(newDBRow.GetType()).Find(KeysNeededHere); //Unable to get the entity keys.
I tried to use the entry, but SysRowID is still blank at CurrentValues. Also, I tried to use the Find but it needs keys and I can't add the ClientNum since I want to do it in a generic way for all entities.
DbSet.Find method expect the value of the key. If SysRowID is not defined as your key this method will never return a value even if SysRowID has the correct value.
Database First:
If you are using Database First, then in your EDMX model just right click on your property SysRowID and click on Properties, then change the StoreGeneratedPattern value to Computed.
Code First:
If you are using Code First approach then you must decorate your property SysRowID with DatabaseGenerated attribute and pass DatabaseGeneratedOption.Computedas a parameter to the constructor of the attribute. At the end you will have this code on your property
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public System.Guid? SysRowID { get; set; }
By doing this either you are in Code First or Database First, EF will know that this property is computed by the database and it will retrieve it after insert success.
I think I am missing something simple here. I am getting the error:
"Violation of PRIMARY KEY constraint 'PK_FeatureTypes'. Cannot insert duplicate key in object 'dbo.FeatureTypeCodes'. The duplicate key value is (28).\r\nThe statement has been terminated"
I have a look-up / linked table of FeatureType - (Mountain, Lake, River, etc.) which is already populated with data and is defined as:
[Table("FeatureTypeCodes")]
public class FeatureTypeCode {
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int FeatureTypeCodeID { get; set; }
public string Name { get; set; }
}
This is linked to my place table / object like this:
[Table("Places")]
public class Place {
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int PlaceID { get; set; }
public string Name { get; set; }
public FeatureTypeCode FeatureTypeCode { get; set; }
public ICollection<PlaceCoordinate> PlaceCoordinates { get; set; }
}
Then I am loading them from the old database like this (it is part of my conversion code):
foreach (DataRow r in table.Rows) {
int ftID = Convert.ToInt32(r["FeatureTypeId"]);
Place temp = new Place {
PlaceID = Convert.ToInt32(r["PlaceID"]),
Name = r["PlaceName"].ToString(),
FeatureTypeCode = featureTypeCodeRepository.FeatureTypeCodes.FirstOrDefault(o=>o.FeatureTypeCodeID == ftID)
};
places.Add(temp);
}
The error is being generated when it tries to insert a new FeatureType object with the same ID as an existing object while saving a Place. My thought was that by loading FeatureType from the context it would not attempt to insert a new FeatureType on saving the Place object. I am obviously wrong on that, but is it something simple I am missing?
I don't think that you use the same DBContext Object in your featureTypeCodeRepository and the places.Add(temp);. So I think that basically EF don't keep track of the FeatureTypeCodes becuse it's loaded by one context, and saved by another.
While I think that Simon Edström is right (+1), you may also consider to expose the primitive foreign key field (something like FeatureTypeId?) in your Place class. Then you can simply set
FeatureTypeId = ftID;
If you're not sure whether the FK field value really exists in the FeatureTypeCodes table, you can query for its existence using the featureTypeCodeRepository even when it has a different context. Using Any() is the cheapest way to do that:
var exists = featureTypeCodeRepository.FeatureTypeCodes
.Any(o => o.FeatureTypeCodeID == ftID)
It is not uncommon to do this in entity framework. Relationships consisting of only a reference (like Place.FeatureTypeCode) are called independent associations, those with a reference and a primitive FK property foreign key associations. Julia Lerman in her book DbContext says
unless you have a very
good reason not to expose the foreign key properties you will save yourself a lot of pain
by including them
I've written an app that I use as an agent to query data from a database and automatically load it into my distributed web cache.
I do this by specifying an sql query and a type in a configuration. The code that actually does the querying looks like this:
List<Object> result = null;
try { result = dc.ExecuteQuery(elementType, entry.Command).OfType<Object>().ToList(); }
catch (Exception ex) { HandleException(ex, WebCacheAgentLogEvent.DatabaseExecutionError); continue; }
elementType is a System.Type created from the type specified in the configuration (using Type.GetType()), and entry.Command is the SQL query.
The specific entity type I'm having an issue with looks like this:
public class FooCount
{
[Column(Name = "foo_id")]
public Int32 FooId { get; set; }
[Column(Name = "count")]
public Int32 Count { get; set; }
}
The SQL query looks like this:
select foo_id as foo_id, sum(count) as [count]
from foo_aggregates
group by foo_id
order by foo_id
For some reason, when the query is executed, the "Count" property ends up populated, but not the "FooId" property. I tried running the query myself, and the correct column names are returned, and the column names match up with what I've specified in my mapping attributes. Help!
This is insane...
What fixed my problem was decorating my entity class with TableAttribute:
[Table(Name = "foo_aggregates")]
public class FooCount
{
[Column(Name = "foo_id")]
public Int32 FooId { get; set; }
[Column(Name = "count")]
public Int32 Count { get; set; }
}
I had assumed (wrongly, apparently) that since I wasn't using the GetTable<T>() method, I didn't need the corresponding mapping attribute.
Update: A year and a half later, it finally dawned on me it seems like the ColumnAttribute decorations on the properties are ignored unless there's a corresponding TableAttribute decoration on the class. This explains why the "Count" property was getting populated, since its naming would match the column in the SQL statement, whereas FooId/foo_id of course do not match.
Linq To Sql has a hard time mapping stuff when the names of the properties are different than the names of the columns. Try changing your property name to foo_id with the underscore. That should to the trick.
Either that, or you can change your select statement to foo_id as FooId to match your property. Either way, they should be the same (don't need to be the same case though).