YamlDotNet throwing exception when deserializing object - yamldotnet

So, I am new to Yaml and YamlDotNet. I wrote the following code to parse a yaml file I am using for configuration of an client API...
public bool TryGet(string path, out DiagnosticScannerConfig config)
{
var deserializer = new DeserializerBuilder()
.WithNamingConvention(new HyphenatedNamingConvention())
.Build();
try
{
using (var reader = File.OpenText(path))
{
var deserializedConfig = deserializer.Deserialize<InternalDiagnosticScannerConfig>(reader);
config = new DiagnosticScannerConfigImpl(deserializedConfig);
return true;
}
}
catch (Exception e)
{
config = DiagnosticAnalyzerConfigCache.Default;
return true;
}
}
public interface DiagnosticScannerConfig
{
DiagnosticAnalyzerConfig Analyzer { get; }
}
public interface DiagnosticAnalyzerConfig
{
uint HighClosureRateWarningThreshold { get; }
uint HighCreationRateWarningThreshold { get; }
uint QueueHighFlowThreshold { get; }
uint QueueLowFlowThreshold { get; }
decimal MessageRedeliveryCoefficient { get; }
decimal SocketUsageCoefficient { get; }
decimal RuntimeProcessUsageCoefficient { get; }
decimal FileDescriptorUsageWarningCoefficient { get; }
decimal ConsumerUtilizationWarningCoefficient { get; }
}
class DiagnosticScannerConfigImpl : DiagnosticScannerConfig
{
public DiagnosticScannerConfigImpl(InternalDiagnosticScannerConfig config)
{
Analyzer = new DiagnosticAnalyzerConfigImpl(config.Analyzer);
}
class DiagnosticAnalyzerConfigImpl : DiagnosticAnalyzerConfig
{
public DiagnosticAnalyzerConfigImpl(Analyzer config)
{
HighClosureRateWarningThreshold = config.HighClosureRateWarningThreshold;
HighCreationRateWarningThreshold = config.HighCreationRateWarningThreshold;
QueueHighFlowThreshold = config.QueueHighFlowThreshold;
QueueLowFlowThreshold = config.QueueLowFlowThreshold;
MessageRedeliveryCoefficient = config.MessageRedeliveryCoefficient;
SocketUsageCoefficient = config.SocketUsageCoefficient;
RuntimeProcessUsageCoefficient = config.RuntimeProcessUsageCoefficient;
FileDescriptorUsageWarningCoefficient = config.FileDescriptorUsageWarningCoefficient;
ConsumerUtilizationWarningCoefficient = config.ConsumerUtilizationWarningCoefficient;
}
public uint HighClosureRateWarningThreshold { get; }
public uint HighCreationRateWarningThreshold { get; }
public uint QueueHighFlowThreshold { get; }
public uint QueueLowFlowThreshold { get; }
public decimal MessageRedeliveryCoefficient { get; }
public decimal SocketUsageCoefficient { get; }
public decimal RuntimeProcessUsageCoefficient { get; }
public decimal FileDescriptorUsageWarningCoefficient { get; }
public decimal ConsumerUtilizationWarningCoefficient { get; }
}
public DiagnosticAnalyzerConfig Analyzer { get; }
}
public class Analyzer
{
[YamlMember(Alias = "high-closure-rate-warning-threshold")]
public uint HighClosureRateWarningThreshold { get; set; }
[YamlMember(Alias = "high-creation-rate-warning-threshold")]
public uint HighCreationRateWarningThreshold { get; set; }
[YamlMember(Alias = "queue-high-flow-threshold")]
public uint QueueHighFlowThreshold { get; set; }
[YamlMember(Alias = "queue-low-flow-threshold")]
public uint QueueLowFlowThreshold { get; set; }
[YamlMember(Alias = "message-redelivery-coefficient")]
public decimal MessageRedeliveryCoefficient { get; set; }
[YamlMember(Alias = "socket-usage-coefficient")]
public decimal SocketUsageCoefficient { get; set; }
[YamlMember(Alias = "runtime-process-usage-coefficient")]
public decimal RuntimeProcessUsageCoefficient { get; set; }
[YamlMember(Alias = "file-descriptor-usage-warning-coefficient")]
public decimal FileDescriptorUsageWarningCoefficient { get; set; }
[YamlMember(Alias = "consumer-utilization-warning-coefficient")]
public decimal ConsumerUtilizationWarningCoefficient { get; set; }
}
public class InternalDiagnosticScannerConfig
{
public Analyzer Analyzer { get; }
}
I trying to parse the following yaml file:
---
high-closure-rate-warning-threshold: 90
high-creation-rate-warning-threshold: 60
queue-high-flow-threshold: 90
queue-low-flow-threshold: 10
message-redelivery-coefficient: 0.60
socket-usage-coefficient: 0.60
runtime-process-usage-coefficient: 0.65
file-descriptor-usage-warning-coefficient: 0.65
consumer-utilization-warning-coefficient: 0.65
...
When I execute the above code I am getting the following error:
YamlDotNet.Core.YamlException: (Line: 2, Col: 5, Idx: 8) - (Line: 2, Col: 5, Idx: 8): Exception during deserialization ---> System.Runtime.Serialization.SerializationException: Property 'high-closure-rate-warning-threshold' not found on type 'HareDu.Diagnostics.Configuration.InternalDiagnosticScannerConfig'.
at YamlDotNet.Serialization.TypeInspectors.TypeInspectorSkeleton.GetProperty(Type type, Object container, String name, Boolean ignoreUnmatched)
at YamlDotNet.Serialization.NodeDeserializers.ObjectNodeDeserializer.YamlDotNet.Serialization.INodeDeserializer.Deserialize(IParser parser, Type expectedType, Func`3 nestedObjectDeserializer, Object& value)
at YamlDotNet.Serialization.ValueDeserializers.NodeValueDeserializer.DeserializeValue(IParser parser, Type expectedType, SerializerState state, IValueDeserializer nestedObjectDeserializer)
--- End of inner exception stack trace ---
at YamlDotNet.Serialization.ValueDeserializers.NodeValueDeserializer.DeserializeValue(IParser parser, Type expectedType, SerializerState state, IValueDeserializer nestedObjectDeserializer)
at YamlDotNet.Serialization.ValueDeserializers.AliasValueDeserializer.DeserializeValue(IParser parser, Type expectedType, SerializerState state, IValueDeserializer nestedObjectDeserializer)
at YamlDotNet.Serialization.Deserializer.Deserialize(IParser parser, Type type)
at YamlDotNet.Serialization.Deserializer.Deserialize[T](IParser parser)
at YamlDotNet.Serialization.Deserializer.Deserialize[T](TextReader input)
at HareDu.Diagnostics.Configuration.DiagnosticScannerConfigProvider.TryGet(String path, DiagnosticScannerConfig& config) in /Users/albert/Documents/Git/HareDu2/src/HareDu.Diagnostics/Configuration/DiagnosticScannerConfigProvider.cs:line 59

The exception message is telling you the problem: your type InternalDiagnosticScannerConfig does not have a 'high-closure-rate-warning-threshold' property. Indeed on your code that property is defined in the Analyzer class. You should either deserialize to that type, or update your YAML so that it's structure reflects your classes.
In practice, either use this:
deserializer.Deserialize<InternalDiagnosticScannerConfig>(reader);
Or this:
---
analyzer:
high-closure-rate-warning-threshold: 90
high-creation-rate-warning-threshold: 60
queue-high-flow-threshold: 90
queue-low-flow-threshold: 10
message-redelivery-coefficient: 0.60
socket-usage-coefficient: 0.60
runtime-process-usage-coefficient: 0.65
file-descriptor-usage-warning-coefficient: 0.65
consumer-utilization-warning-coefficient: 0.65
...

Related

Is there a way to treat sequences as single mappings in yamldotnet?

I have a third party YAML data that I need to deserialize modify then serialize and send back. The problem being that their data is formatted so every entry is its own sequence. I was able to come up with a type converter that will serialize the data, but before I write the serializer for this I wanted to see if there was a better way to go about this.
YAML:
---
Message:
- Name: GENCBL
- Style: 1x7 Western Fixed
- PrintDelay: 0
- PrintCount: 90
- Orientation:
- Rotation: 0
- HFlip: False
- VFlip: False
- Printer:
- Type: 8900
- Pitch:
- Horizontal: 320
- VerticalAdj: 0
- Line:
- Field:
- Name: Field 1
- Type: Text
- Visibility: True
- Rotation: 0
- Negative: False
- Locale: en_GB
- Boldness: 1
- Pos:
- X: 25
- Y: 0
- Font:
- Name: Universal
- Size: 7
- Units: Drops
- Rotation: 0
- Parameters:
- Text: FEET
- Field:
- Name: Field 1
- Type: Text
- Visibility: True
- Rotation: 0
- Negative: False
- Locale: en_GB
- Boldness: 1
- Pos:
- X: 502
- Y: 0
- Font:
- Name: Universal
- Size: 7
- Units: Drops
- Rotation: 0
- Parameters:
- Text: ---
- Field:
- Name: Field 1
- Type: Date
- Visibility: True
- Rotation: 0
- Negative: False
- Locale: en_GB
- Boldness: 1
- Pos:
- X: 968
- Y: 0
- Font:
- Name: Universal
- Size: 7
- Units: Drops
- Rotation: 0
- Parameters:
- Format: ""%MM%""
- Offset:
- Time: 0:0
...
TypeConverter:
public class SequenceConverter<T> : IYamlTypeConverter where T: new()
{
/// <summary>
/// Gets a value indicating whether the current converter supports converting the specified type.
/// </summary>
public bool Accepts(Type type)
{
return typeof(T).IsAssignableFrom(type);
}
/// <summary>Reads an object's state from a YAML parser.</summary>
public object ReadYaml(IParser parser, Type type)
{
var baseObject = new T();
parser.Consume<SequenceStart>();
while (parser.Current is MappingStart)
{
ParseNextField(parser, baseObject);
}
parser.Consume<SequenceEnd>();
return baseObject;
}
private static void ParseNextField(IParser parser, object current)
{
parser.Consume<MappingStart>();
Scalar key = parser.Consume<Scalar>();
var keyValue = key.Value;
if (keyValue == "Offset")
{
keyValue = parser.Current is Scalar ? "OffsetString" : "OffsetObject";
}
System.Reflection.PropertyInfo propInfo = current.GetType().GetProperty(keyValue);
if (propInfo != null)
{
if (parser.TryConsume(out Scalar value))
{
if (propInfo.PropertyType.IsValueType || propInfo.PropertyType == typeof(string))
{
propInfo.SetValue(current, Convert.ChangeType(value.Value, propInfo.PropertyType));
}
}
else if (parser.TryConsume<SequenceStart>(out _))
{
if (typeof(IList).IsAssignableFrom(propInfo.PropertyType))
{
if (propInfo.GetValue(current) == null)
{
object propInstance = Activator.CreateInstance(propInfo.PropertyType);
propInfo.SetValue(current, propInstance);
}
var list = propInfo.GetValue(current) as IList;
var childInstance = Activator.CreateInstance(propInfo.PropertyType.GetGenericArguments().First());
list?.Add(childInstance);
while (parser.Current is MappingStart)
{
ParseNextField(parser, childInstance);
}
}
else
{
object propInstance = Activator.CreateInstance(propInfo.PropertyType);
propInfo.SetValue(current, propInstance);
while (parser.Current is MappingStart)
{
ParseNextField(parser, propInstance);
}
}
parser.Consume<SequenceEnd>();
}
}
parser.Consume<MappingEnd>();
}
/// <summary>
/// Writes the specified object's state to a YAML emitter.
/// </summary>
public void WriteYaml(IEmitter emitter, object value, Type type)
{
throw new NotImplementedException();
}
}
Serialization Classes:
public class Message
{
public string Name { get; set; }
public string Style { get; set; }
public int PrintDelay { get; set; }
public int PrintCount { get; set; }
public Orientation Orientation { get; set; }
public PrinterDetails Printer { get; set; }
public List<Line> Line { get; set; }
}
public class Orientation
{
public int Rotation { get; set; }
public bool HFlip { get; set; }
public bool VFlip { get; set; }
}
public class PrinterDetails
{
public string Type { get; set; }
public Pitch Pitch { get; set; }
}
public class Pitch
{
public int Horizontal { get; set; }
public int VerticalAdj { get; set; }
}
public class Line
{
public List<Field> Field { get; set; }
}
public class Field
{
public string Name { get; set; }
public string Type { get; set; }
public bool Visibility { get; set; }
public int Rotation { get; set; }
public bool Negative { get; set; }
public string Locale { get; set; }
public int Boldness { get; set; }
public Position Pos { get; set; }
public Font Font { get; set; }
public Parameters Parameters { get; set; }
}
public class Parameters
{
public string Format { get; set; }
public string Text { get; set; }
public string Start { get; set; }
public string Stop { get; set; }
public int Step { get; set; }
public int Repeat { get; set; }
public int CurrentRepeat { get; set; }
public string OffsetString { get; set; }
public Offset OffsetObject { get; set; }
}
public class Offset
{
public string Time { get; set; }
}
public class Position
{
public int X { get; set; }
public int Y { get; set; }
}
public class Font
{
public string Name { get; set; }
public int Size { get; set; }
public string Units { get; set; }
public int Rotation { get; set; }
}

AutoMapper 6 - How can I create a mapping that ignore and map a list of object

I'm a little newbie on AutoMapper, I don't find almost nothing about v6.0 on Stackoverflow and Github. I need help on this problem
I have this two Entities:
public class DocFinanceiro
{
public int AutoId { get; set; }
public virtual ICollection<QuitacaoDocFinan> QuitacoesDocFinan { get; set; }
}
public class QuitacaoDocFinan
{
public int AutoId { get; set; }
public int DocFinanceiroId { get; set; }
public virtual DocFinanceiro DocFinanceiro { get; set; }
public decimal ValorTotal { get; set; }
}
}
And his ViewModels:
public class DocFinanceiroViewModel
{
public DocFinanceiroViewModel()
{
ValorPago = QuitacoesDocFinan.Where(x => x.Cancelada == false).Sum(x => x.ValorTotal);
}
public virtual ICollection<QuitacaoDocFinanViewModel> QuitacoesDocFinan { get; set; }
public decimal ValorPago { get; set; }
}
public class QuitacaoDocFinanViewModel
{
public int AutoId { get; set; }
public int DocFinanceiroId { get; set; }
public virtual DocFinanceiroViewModel DocFinanceiro { get; set; }
public decimal ValorTotal { get; set; }
}
And mapping between DocFinanceiro and DocFinanceiroViewModel:
public class DomainToViewModelMappingProfile : Profile
{
public DomainToViewModelMappingProfile()
{
CreateMap<DocFinanceiro, DocFinanceiroViewModel>().ForMember(x => x.ValorPago, y => y.Ignore())
.MaxDepth(3)
.PreserveReferences();
CreateMap<QuitacaoDocFinan, QuitacaoDocFinanViewModel>();
}
}
This mapping works when I set only one of these property
.ForMember(x => x.ValorPago, y => y.Ignore())
or
.MaxDepth(1).PreserveReferences();
, but when I try two cause an exception. I search on everywhere, but no success.
And controller where that I make the mapping:
var documentos = Mapper.Map<IEnumerable<DocFinanceiro>, IEnumerable<DocFinanceiroViewModel>>(*repository*);
Sorry if make some mistake, but I don't what to do...
You are trying to access QuitacoesDocFinan collection in DocFinanceiroViewModel constructor before initializing. Your DocFinanceiroViewModel should be something like this:
public class DocFinanceiroViewModel
{
public virtual ICollection<QuitacaoDocFinanViewModel> QuitacoesDocFinan { get; set; }
public decimal ValorPago
{
get
{
return QuitacoesDocFinan.Where(x => x.Cancelada == false).Sum(x => x.ValorTotal);
}
}
}

Complex Automapper Configuration

I'm mapping from an existing database to a DTO and back again use Automapper (4.1.1) and I've hit a few small problems.
I have a (simplified) model for the database table:
public class USER_DETAILS
{
[Key]
public string UDT_LOGIN { get; set; }
public string UDT_USER_NAME { get; set; }
public string UDT_INITIALS { get; set; }
public string UDT_USER_GROUP { get; set; }
public decimal UDT_CLAIM_LIMIT { get; set; }
public string UDT_CLAIM_CCY { get; set; }
}
and a DTO object:
public class User
{
public string Login { get; set; }
public string UserName { get; set; }
public string Initials { get; set; }
public string UserGroup { get; set; }
public double ClaimLimit { get; set; }
public string ClaimCurrency { get; set; }
}
I've created a profile
public class FromProfile : Profile
{
protected override void Configure()
{
this.RecognizePrefixes("UDT_");
this.ReplaceMemberName("CCY", "Currency");
this.SourceMemberNamingConvention = new UpperUnderscoreNamingConvention();
this.DestinationMemberNamingConvention = new PascalCaseNamingConvention();
this.CreateMap<decimal, double>().ConvertUsing((decimal src) => (double)src);
this.CreateMap<USER_DETAILS, User>();
}
}
However, it seems that Automapper doesn't like combining this many settings in the config. Even simplifying the models, I can't get
this.RecognizePrefixes("UDT_");
this.ReplaceMemberName("CCY", "Currency");
to work together, and whilst
this.CreateMap<decimal, double>().ConvertUsing((decimal src) => (double)src);
works ok with the models in the test, it fails when using it against a database.
Is there a way to get all this to work together, or should I fall back to using ForMember(). I was really hoping I could get this working as there are a lot of tables in this system, and I'd rather not have to do each one individually.
You will need to extend this for other types, only tested with strings, I have an extension method that does all the work and looks for unmapped properties.
public class USER_DETAILS
{
public string UDT_LOGIN { get; set; }
public string UDT_USER_NAME { get; set; }
public string UDT_INITIALS { get; set; }
public string UDT_USER_GROUP { get; set; }
// public decimal UDT_CLAIM_LIMIT { get; set; }
public string UDT_CLAIM_CCY { get; set; }
}
public class User
{
public string Login { get; set; }
public string UserName { get; set; }
public string Initials { get; set; }
public string UserGroup { get; set; }
//public double ClaimLimit { get; set; }
public string ClaimCurrency { get; set; }
}
public static class AutoMapperExtensions
{
public static IMappingExpression<TSource, TDestination>
CustomPropertyMapper<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
{
var sourceType = typeof(TSource);
var destinationType = typeof(TDestination);
var existingMaps = Mapper.GetAllTypeMaps().First(x => x.SourceType == sourceType && x.DestinationType == destinationType);
var properties = sourceType.GetProperties();
foreach (var property in existingMaps.GetUnmappedPropertyNames())
{
var similarPropertyName =
properties.FirstOrDefault(x => x.Name.Replace("_", "").Replace("UDT", "").ToLower().Contains(property.ToLower()));
if(similarPropertyName == null)
continue;
var myPropInfo = sourceType.GetProperty(similarPropertyName.Name);
expression.ForMember(property, opt => opt.MapFrom<string>(myPropInfo.Name));
}
return expression;
}
}
class Program
{
static void Main(string[] args)
{
InitializeAutomapper();
var userDetails = new USER_DETAILS
{
UDT_LOGIN = "Labi-Login",
UDT_USER_NAME = "Labi-UserName",
UDT_INITIALS = "L"
};
var mapped = Mapper.Map<User>(userDetails);
}
static void InitializeAutomapper()
{
Mapper.CreateMap<USER_DETAILS, User>().CustomPropertyMapper();
}
}
}

Mapping into differnet types with Automapper

There are two classes in my Model:
public class Operation
{
public string Name { get; set; }
public Calculation Details { get; set; }
}
public class Calculation
{
public long Value { get; set; }
public List<decimal> Points { get; set; }
}
Mapping into this DTO:
public class OperationDto
{
public string Name { get; set; }
public CalculationDto Details { get; set; }
}
public class CalculationDto
{
public long Value { get; set; }
}
public class CalculationDetailedDto: CalculationDto
{
public List<decimal> Points { get; set; }
}
And sometimes the Client can request detailed information about the calculation. For example, depending of the command-line options:
class Program
{
static void Main(string[] args)
{
Mapper.CreateMap<Operation, OperationDto>();
Mapper.CreateMap<Calculation, CalculationDto>();
Mapper.CreateMap<Calculation, CalculationDetailedDto>();
var operation = new Operation
{
Name = "Very complicated opertion.",
Details =
new Calculation
{
Value = 1002,
Points = new List<decimal> {1.2m, 2.4m, 3.7m}
}
};
var operationDto = Mapper.Map<OperationDto>(operation);
Debug.WriteLine("Operation name: '{0}' value: '{1}'", operationDto.Name, operationDto.Details.Value);
if (args.Length > 0)
{
Debug.WriteLine("Details:");
foreach (var point in ((CalculationDetailedDto) operationDto.Details).Points)
{
Debug.WriteLine("{0}", point);
}
}
}
How do i tell Automapper at runtime map the calculation into CalculationDetailedDto?
You need to create another OperationDto that uses the detailed calculationDto, and create a map from Operation to OperationDetailedDto:
public class OperationDetailedDto
{
public string Name { get; set; }
public CalculationDetailedDto Details { get; set; }
}
Mapper.CreateMap<Operation, OperationDetailedDto>();
if (detailed) operationDto = Mapper.Map<Operation, OperationDto>(operation);
else operationDto = Mapper.Map<Operation, OperationDetailedDto(operation);
For those who do not fit solution proposed #fiskeboss can use the following.
You can re-map Calculation to CalculationDetailedDto after checking the command line arguments.
if (args.Length > 0)
{
operationDto.Details = Mapper.Map<CalculationDetailedDto>(operation.Details);
Debug.WriteLine("Details:");
foreach (var point in ((CalculationDetailedDto) operationDto.Details).Points)
{
Debug.WriteLine("{0}", point);
}
}

entity framework looking in different table during unittests

I have a single DbContext in a library along with entities and their configuration in fluent api.
I use this same context in two different projects.
The first one is a test project and the second one a simple console application.
I execute a query including some of it's relations like this:
var vacancies = (from v in ctx.Vacancies
.Include("Categories")
.Include("Levels")
.Include("Contracts")
.Include("JobTypes"));
Strangely enough the console application works perfectly, however the unittest starts looking in the wrong tables all of a sudden.
Both applications produce very different queries when i look at them.
I'm using EF5 atm and I've been stuck on this for a few days now with not a single clue to what might cause this problem.
EDIT:
The point is i don't do any different queries, i also only have on context and only one connectionstring which i have confirmed during runtime connects to the right database.
All i can say is that i feel like the fluent api has no effect in unittests even though it hits the code just fine like it should.
public class SchedulerContext : BaseContext<SchedulerContext>{
public DbSet<Click> Clicks { get; set; }
public DbSet<Category> Categories { get; set; }
public DbSet<ContractType> Contracts { get; set; }
public DbSet<JobType> JobTypes { get; set; }
public DbSet<Level> Levels { get; set; }
public DbSet<ExternalMapping> ExternalMappings { get; set; }
public DbSet<GeoName> GeoNames { get; set; }
public DbSet<GeoAlternateName> GeoAlternateNames { get; set; }
public DbSet<Trigger> JobTriggers { get; set; }
public DbSet<RegistryValue> RegistryValues { get; set; }
public DbSet<JobResult> JobResults { get; set; }
public DbSet<JobInfo> JobInfo { get; set; }
public DbSet<JobError> JobErrors { get; set; }
public DbSet<JobNotification> JobNotifications { get; set; }
public DbSet<Company> Customers { get; set; }
public DbSet<Vacancy> Vacancies { get; set; }
public SchedulerContext() {
//this.Configuration.ProxyCreationEnabled = false;
//this.Configuration.LazyLoadingEnabled = false;
}
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
modelBuilder.Configurations.Add(new VacancyEntityTypeConfiguration());
base.OnModelCreating(modelBuilder);
}
}
That is my context.
And my entity configuration:
public class VacancyEntityTypeConfiguration : EntityTypeConfiguration<Vacancy> {
public VacancyEntityTypeConfiguration() {
this.HasMany(c => c.Levels).
WithMany().
Map(
m => {
m.ToTable("VacancyLevels");
});
this.HasMany(c => c.Categories).
WithMany().
Map(
m => {
m.ToTable("VacancyCategories");
});
this.HasMany(c => c.Contracts).
WithMany().
Map(
m => {
m.ToTable("VacancyContractTypes");
});
this.HasMany(c => c.Jobtypes).
WithMany().
Map(
m => {
m.ToTable("VacancyJobTypes");
});
}
}
And the exact method which shows the problem.
public List<Vacancy> GetVacanciesForCustomer(Company customer, bool onlineInclusive) {
using (var ctx = new JHSchedulerContext.SchedulerContext()) {
var vacancies = (from v in ctx.Vacancies.Include("Categories").Include("Levels").Include("Contracts").Include("JobTypes") where v.SourceSite == customer.SourceSite && (v.Online || onlineInclusive == false) select v).ToList();
return vacancies.ToList();
}
}
And the Vacancy class:
public class Vacancy {
public Vacancy()
{
this.Language = "";
}
[SolrUniqueKey("id")]
[Key]
[Required]
public int Id { get; set; }
[StringLength(50, ErrorMessage = "Maximum length 50 characters")]
public string ExternalId { get; set; }
[SolrField("title")]
[StringLength(1024, ErrorMessage = "Maximum length 1024 characters")]
public string Title { get; set; }
[SolrField("company")]
[StringLength(1024, ErrorMessage = "Maximum length 1024 characters")]
public string Company { get; set; }
[StringLength(4096, ErrorMessage = "Maximum length 4096 characters")]
public string CompanyText { get; set; }
[SolrField("location")]
[StringLength(1024, ErrorMessage = "Maximum length 1024 characters")]
public string Location { get; set; }
[SolrField("url")]
[StringLength(1024, ErrorMessage = "Maximum length 1024 characters")]
public string Url { get; set;}
[SolrField("source")]
[StringLength(1024, ErrorMessage = "Maximum length 1024 characters")]
public string SourceSite { get; set; }
private string text;
[SolrField("text")]
[StringLength(4096, ErrorMessage = "Maximum length 4096 characters")]
public string Text {
get {
return StringHelper.TruncateAtWord(text, 500);
//return new String(text.Take(500).ToArray());
//return text.Substring(text.Length < 900 ? 0 : (text.Length / 2), (int)Math.Min(text.Length, 500));
}
set{
text = value;
}
}
[StringLength(4096, ErrorMessage = "Maximum length 4096 characters")]
public string TextProfile { get; set; }
[StringLength(4096, ErrorMessage = "Maximum length 4096 characters")]
public string TextOffer { get; set; }
[NotMapped]
[ScriptIgnore]
public SqlGeography Coordinate {
get
{
if (Latitude.HasValue && Longitude.HasValue)
return SqlGeography.Point(Latitude.Value, Longitude.Value, 4326);
else
return null;
}
}
[SolrField("coordinate_0_coordinate")]
public double? Latitude { get; set; }
[SolrField("coordinate_1_coordinate")]
public double? Longitude { get; set; }
[StringLength(1024, ErrorMessage = "Maximum length 1024 characters")]
public string NormalizedLocation { get; set; }
public DateTime? ScrapedDate { get; set; }
[SolrField("insertdate")]
public DateTime? ImportDate { get; set; }
public DateTime? ExpireDate { get; set; }
[NotMapped]
public string DaysAgo {
get {
if (ImportDate != null)
return (DateTime.Now - (DateTime)ImportDate).Days.ToString();
else {
return "N/A";
}
}
}
[SolrField("category")]
public ICollection<string> CategoryNames {
get { return Categories != null ? Categories.Select(c => c.Name).ToList() : null; }
}
[SolrField("level")]
public ICollection<string> LevelNames {
get { return Levels != null ? Levels.Select(l => l.Name).ToList() : null; }
}
[SolrField("contract")]
public ICollection<string> ContractNames {
get { return Contracts != null ? Contracts.Select(c => c.Name).ToList() : null; }
}
[SolrField("time")]
public ICollection<string> JobTypeNames {
get { return Jobtypes != null ? Jobtypes.Select(c => c.Name).ToList() : null; }
}
public string ContactName { get; set; }
[Required]
public bool Online { get; set; }
[NotMapped]
public int? Distance { get; set; }
public string Language { get; set; }
public string PriorityType { get; set; }
public int NumClicks { get; set; }
[NotMapped]
public string GridContactName {
get{
return string.Format("{0} (Total Clicks:{1})",ContactName,NumClicks);
}
}
public virtual ICollection<Level> Levels { get; set; }
public virtual ICollection<Category> Categories { get; set; }
public virtual ICollection<ContractType> Contracts { get; set; }
public virtual ICollection<JobType> Jobtypes { get; set; }
public override string ToString() {
return string.Format("Id={0} ExternalId={1} Title={2} Company={3} Location={4} Url={5} SourceSite={6} Text={7} NormalizedLocation={8} InsertDate={9} ImportDate={10} DaysAgo={11}",Id, ExternalId,Title,Company,Location,Url, SourceSite,Text,NormalizedLocation,ScrapedDate,ImportDate,DaysAgo);
}
}
And the Level class(all the other relation classes have the same structure(name,id):
public class Level {
[Key]
[Required]
public int Id { get; set; }
[Required]
[StringLength(100, ErrorMessage = "Maximum length 100 characters")]
public string Name { get; set; }
public override string ToString() {
return string.Format("Id={0} Name={1}", Id, Name);
}
}
As far as connection to database goes you'll just have to believe me that i've checked both are connecting to the same database.(I even generated a new database with migrations enabled on this one since we use another context for migrations. That still had the exact same issue).
To clarify:
The unittest looks for table: CategoryVacancies.
The console application or even my windows service i use this in look for the right table: VacancyCategories.

Resources