I keep running into this error:
An unhandled exception of type 'CsvHelper.CsvReaderException' occurred in CsvHelper.dll
Additional information: No properties are mapped for type 'RPS_String_Parse.Program+FormattedRow'.
But I believe I am following the documentation correctly. After referencing the "getting started" portion i implemented this:
using (var sr = new StreamReader(filePath))
{
var csv = new CsvReader(sr);
var records = csv.GetRecords<FormattedRow>();
foreach (var record in records)
{
Console.WriteLine(record.Address1);
}
Console.ReadLine();
}
and my class:
public class FormattedRow
{
public string IDOrderAlpha;
public string IDOrder;
public string AddressCompany;
public string Address1;
public string Address2;
public string AddressCity;
public string AddressState;
public string AddressZip;
public string AddressCountry;
public string ShipMethod;
public string ContactEmail;
public string ContactName;
public string ServiceRep;
public string CustomerPuchaseOrder;
}
I feel like this should work, because the documentation states:
Auto Mapping
If you don't supply a mapping file, auto mapping will be
used. Auto mapping will map the properties in your class in the order
they appear in. If the property is a custom class, it recursively maps
the properties from that class in the order they appear in. If the
auto mapper hits a circular reference, it will stop going down that
reference branch
What am I missing?
The documentation states that it will map to Properties. Your class has Fields. Make this change:
public class FormattedRow
{
public string IDOrderAlpha { get; set; }
// add { get; set; } for all
}
This will change your fields to "auto properties".
You need to set the configuration options for mapping:
var generatedMap = csv.Configuration.AutoMap<MyClass>();
So it appears you need to tell it to automap. I've never used this library before.
Edit: Jon B nailed it.
Related
I am trying to use a custom attribute on a Entity class generated automatically by the Entity Framework.
The problem is how to add an property attribute on an existing field?
Here the point where I am right now:
// the custom attribute class
public class MyCustomAttribute : Attribute
{
public String Key { get; set; }
}
// Entity Framework class generated automatically
public partial class EntityClass
{
public String Existent { get; set; }
//...
}
// set a metadata class for my entity
[MetadataType(typeof(EntityClassMetaData))]
public partial class EntityClass
{
// if I add a new property to the entity, it works. This attribute will be read
[MyCustomAttribute(Key = "KeyOne" )]
public int newProp { get; set; }
}
public class EntityClassMetaData
{
// adding the custom attribute to the existing property
[MyCustomAttribute(Key = "keyMeta") ]
public String Existent { get; set; }
}
Running this test:
[TestMethod]
public void test1()
{
foreach (var prop in typeof(EntityClass).GetProperties())
{
var att = prop.GetCustomAttribute<MyCustomAttribute>();
if (att != null)
{
Console.WriteLine($"Found {att.Key}");
}
}
}
will produce:
Found KeyOne
Or the Metadata class store the attribute in a different way or only works for data annotations.
I am stuck here, how can I set and read custom attributes of the generated class without having to edit the generated file?
I came across this same problem today. I figured EF magic would do the trick and map the attribute across to each model property. Turns out it does, but only for EF data annotations and I couldn't find an answered solution to pull out custom attributes so made this function. Hope it helps dude.
private object[] GetMetadataCustomAttributes(Type T, string propName)
{
if (Attribute.IsDefined(T, typeof(MetadataTypeAttribute)))
{
var metadataClassType =
(T.GetCustomAttributes(typeof(MetadataTypeAttribute), true).FirstOrDefault() as
MetadataTypeAttribute).MetadataClassType;
var metaDataClassProperty = metadataClassType.GetProperty(propName);
if (metaDataClassProperty != null)
{
return metaDataClassProperty.GetCustomAttributes(true);
}
}
return null;
}
I believe if you want to set an attribute in the metadata class, you have to use this syntax:
public class EntityClassMetaData
{
// adding the custom attribute to the existing property
[MyCustomAttribute(Key = "keyMeta") ]
public String Existent;
}
You must not have { get; set; } on your pre-existing property - just the property with the correct name and datatype.
I'm currently working on a Windows Forms application, and I would like to use a simple database which doesn't require a backing server or credentials to run, so I chose SQLite. But trying to get this thing to work so far was a nightmare.
Right now, I have a few, simple classes with simple properties, which I'd like to store in the database. I've appended the appropriate labels to everything ([Table("")] for classes, [PrimaryKey, AutoIncrement] for the Id property), but whenever I do Connection.CreateTable(CreateFlags.AutoIncPK) (it won't show the generic parameter, but it's there, I promise), it throws a NotSupportedException, saying "Don't know about MyProject.MyClass". I have also provided an empty, parameterless constructor in each class.
So, how do I make SQLite "know" about my class?
EDIT:
My Character.cs file:
[Table("Character")]
class Character
{
[PrimaryKey, AutoIncrement]
public int id { get; set; }
public string Name
{
get;
set;
}
public string FilePath
{
get;
set;
}
public Character()
{
}
public Character(string file)
{
this.FilePath = file;
this.Name = FetchName(file);
}
private string FetchName(string file)
{
string[] fileHolder = File.ReadAllLines("\\chars\\" + file);
foreach (string line in fileHolder)
{
if (line.ToLower().StartsWith("name"))
{
if (!line.Contains(';'))
return line.Split('=')[1].Trim().Trim('"');
else return line.Split('=')[1].Split(';')[0].Trim().Trim('"');
}
}
return string.Empty;
}
}
My Database.cs file:
class Database
{
private static SQLiteConnection Connection;
private static string ConnectionString = "MyProject.sqlite";
public Database()
{
if (!File.Exists("MyProject.sqlite"))
System.Data.SQLite.SQLiteConnection.CreateFile("MyProject.sqlite");
using (Connection = new SQLiteConnection(ConnectionString))
{
Connection.CreateTable<Character>(CreateFlags.AutoIncPK);
}
}
}
The class that describe your table has to be public.
In your example, the character class is not public.
You should change the declaration like this:
[Table("Character")]
public class Character
{
// your class code...
}
I know it's a bit late to answer the original question but since my Google-Fu led me here, I hope this will help others that encounter the same error message:
I started receiving this error message after I added as public static property to a class with a [table] attribute. After adding the [Ignore] attribute to the property, I no longer received the error message.
I've inherited a MVC project that seems to use Telerik Open Access to handle data instead of using something I'm more familiar with like entity framework. I'm trying to understand the whole concept of how to work with this data method, but right now I'm just needing to find out how to add a table. I've limited my code examples to one table, but in reality there are dozens of them.
So I see that the class OpenAccessContext.cs has a database connection string, but it also has a IQueryable item made up of the class tblMaterial. The tblMaterial class is defined in tblMaterial.cs. I don't understand how this class is connected to the SQL database version of tblMaterial (so feel free to educate me on that).
I have a table called tblContacts in the SQL database. What do I need to do to connect it to my project? There's no "update from database" option when I right click any object in the solution (because they're all just classes). Will I need to create a new class manually called tblContacts.cs? If so, how do I connect it to the database version of tblContacts? Am I going to need to manually change multiple classes to add the table (OpenAccessContext, MetadataSources, Repository, etc.)?
I tried to keep this as one simple question (how do I add a table) so I don't get dinged, but any light you can shine on the Telerik Open Access would be helpful. (Please don't ding me for asking that!) I checked out the Telerik documentation here: http://docs.telerik.com/data-access/developers-guide/code-only-mapping/getting-started/fluent-mapping-getting-started-fluent-mapping-api , but it's related to setting up a new open access solution. I need to know how to modify one (without ruining the already working code). Thank you in advance for your help!
Here's the solution as seen in Visual Studio:
Open Access
Properties
References
OpenAccessContext.cs
OpenAccessMetadataSources.cs
Repository.cs
tblMaterial.cs
Here's the code:
OpenAccessContext.cs
namespace OpenAccess
{
public partial class OpenAccessContext : OpenAccessContext
{
static MetadataContainer metadataContainer = new OpenAccessMetadataSource().GetModel();
static BackendConfiguration backendConfiguration = new BackendConfiguration()
{
Backend = "mssql"
};
private static string DbConnection = ConfigurationManager.ConnectionStrings["ConnString"].ConnectionString;
private static int entity = ConfigurationManager.AppSettings["Entity"] == "" ? 0 : int.Parse(ConfigurationManager.AppSettings["Entity"]);
public OpenAccessContext() : base(DbConnection, backendConfiguration, metadataContainer)
{
}
public IQueryable<tblMaterial> tblMaterials
{
get
{
return this.GetAll<tblMaterial>(); //.Where(a => a.EntityId == entity);
}
}
}
}
OpenAccessMetadataSources.cs
namespace OpenAccess
{
public class OpenAccessMetadataSource : FluentMetadataSource
{
protected override IList<MappingConfiguration> PrepareMapping()
{
var configurations = new List<MappingConfiguration>();
// tblMaterial
var materialConfiguration = new MappingConfiguration<tblMaterial>();
materialConfiguration.MapType(x => new
{
MaterialId = x.MaterialId,
MaterialName = x.MaterialName,
MaterialDescription = x.MaterialDescription,
MaterialActive = x.MaterialActive,
MaterialUsageType = x.MaterialUsageType,
AddDate = x.AddDate,
AddBy = x.AddBy,
ModDate = x.ModDate,
ModBy = x.ModBy
}).ToTable("tblMaterial");
materialConfiguration.HasProperty(x => x.MaterialId).IsIdentity(KeyGenerator.Autoinc);
}
}
}
Repository.cs
namespace OpenAccess
{
public class Repository : IRepository
{
#region private variables
private static OpenAccessContext dat = null;
#endregion private varibles
#region public constructor
/// <summary>
/// Constructor
/// </summary>
public Repository()
{
if (dat == null)
{
dat = new OpenAccessContext();
}
}
#endregion public constructor
#region Material (tblMaterials)
public int CreateMaterial(tblMaterial itm)
{
try
{
dat.Add(itm);
dat.SaveChanges();
return itm.MaterialId;
}
catch (Exception)
{
return 0;
}
}
}
}
tblMaterial.cs
namespace OpenAccess
{
public class tblMaterial
{
public int MaterialId { get; set; }
public string MaterialName { get; set; }
public string MaterialDescription { get; set; }
public bool MaterialActive { get; set; }
public int MaterialUsageType { get; set; }
public DateTime? AddDate { get; set; }
public string AddBy { get; set; }
public DateTime? ModDate { get; set; }
public string ModBy { get; set; }
}
}
In the case of tblContacts, I would suggest to you the following workflow for extending the model:
Add a new class file that will hold the definition of the tblContact POCO class. In this class add properties that will correspond to the columns of the table. The types of the properties should logically match the datatypes of the table columns.
In the OpenAccessMetadataSource class, add a new MappingConfiguration<tblContact> for the tblContact class and using explicit mapping provide the mapping details that logically connect the tblContact class with the tblContacts table. Make sure to add both the existing and the new mapping configurations to the configurations list.
Expose the newly added class through an IQueryable<tblContact> property in the context. This property will allow you to compose LINQ queries against the tblContacts table.
Regarding the Repository class, it seems like it is related to the custom logic of the application. It surely is not a file generated by Data Access. Therefore, you need to discuss it in your team.
I also strongly advise you against using OpenAccess in the namespaces of your application. This is known to interfere with the Data Access' namespaces during build time and at some point it causes runtime errors.
I hope this helps.
When I use DisplayAttribute in ASP.NET MVC 3 models it quickly becomes a pain writing them because we have to either hardcode the string or reference the string from a some static class that contains const strings (which is what I have now, see below). But even that is too much for me.
I would like to come up with an attribute that would be called something like [SimpleDisplay] and it would implicitly construct the string for resources by looking at
class name,
property name that the attribute is attached to.
Is this possible?
Something like this
public class Product {
[SimpleDisplay] // it will take Product and Name and do something like this Product_Name
public string Name { get; set; }
}
This is what I want to get rid of, if possible:
[Display(ResourceType = typeof(Resources.Localize), Name = ResourceStrings.product_prettyid)]
public virtual int PrettyId
{
get;
set;
}
[Display(ResourceType = typeof(Resources.Localize), Name = ResourceStrings.product_name)]
public virtual string Title
{
get;
set;
}
Now I know that it is not possible to inherit the DisplayAttribute cause it's sealed. What other options I have? Does it even make sense?
I would try creating just a standard attribute and custom DataAnnotationsModelMetadataProvider. You can override CreateMetadata method, which gets IEnumerable<Attribute>. You should than search for your attribute
attributes.OfType<SimpleDisplayAttribute>().FirstOrDefault();
and populate model metadata in any way you want.
If i have a correct understanding what you mean, you may just create a simple custom attribute like this one:
public class LocalizedDisplayNameAttribute : DisplayNameAttribute {
public LocalizedDisplayNameAttribute(string expression) : base(expression) { }
public override string DisplayName {
get {
try {
string[] vals = base.DisplayName.Split(',');
if(vals != null && vals.Length == 2)
return (string)HttpContext.GetGlobalResourceObject(vals[0].Trim(), vals[1].Trim());
} catch {}
return "{res:" + base.DisplayName + "}";
}
}
}
You may then use it as an attribute on your properies. MVC HTML extensions will pickup your custom attribute.
[LocalizedDisplayName("LBL, lbl_name1")]
public string[] Name1 { get; set; }
If I have those two classes that have two different properties but with the same name:
[RdfSerializable]
public class Type1
{
[RdfProperty(true), Name = "title"]
public string Title { get; set; }
}
[RdfSerializable]
public class Type2
{
[RdfProperty(true), Name = "title"]
public string Title { get; set; }
}
and try to serialize them to RDF and validate them with http://www.w3.org/RDF/Validator/ service. Everything is Okay and they are correct.
But after I try to generate OWL files from those classes with OntologyExtractor.exe tool I get that message:
"Ontology extraction failed. http://test.org/1.0#title is assigned to more than one type."
This is strange message as the upper classes are correct and there are some RDF specifications that has same situation with different classes that have same named properties.
I expect it is a bug in ROWLEX. Your case is a valid one, but I assume I did not prepare for it when I wrote OntologyExtractor. I will try to release a fix as soon as possible.
EDIT: ROWLEX2.1 is released, you can download it from http://rowlex.nc3a.nato.int. Version 2.1 (among others) supports now the shared property functionality. The exact code in the question would still result the same error! To overcome that, you should alter the decoration of your code as follows:
[RdfSerializable]
public class Type1
{
[RdfProperty(true, Name = "title", ExcludeFromOntology=true)]
public string Title { get; set; }
}
[RdfSerializable]
public class Type2
{
[RdfProperty(true, Name = "title",
DomainAsType = new Type[]{typeof(Type1), typeof(Type2)})]
public string Title { get; set; }
}
Using the OntologyExtractor.exe, this code will result a OWL property of with an anonymous domain class that is the UNION of Type1 and Type2.
While this is technically perfectly correct solution, setting domains on properties limit their possible future reuse. As a solution, you might want to substitute the property domain with local restrictions. You can achieve that as follows:
[RdfSerializable]
public class Type2
{
[RdfProperty(true, Name = "title",
DomainAsType = new Type[]{typeof(Type1), typeof(Type2)},
UseLocalRestrictionInsteadOfDomain = true)]
public string Title { get; set; }
}
Should you leave UseLocalRestrictionInsteadOfDomain not set, ROWLEX chooses between domain and local restriction according to the current context.