How to replace chars/symbols in a process of writing of csv string/file with CsvHelper? - export-to-csv

I need to get rid of some symbols from each column in a row in a process of writing of csv string but I can't find such feature in CsvHelper.CsvWriter.Configuration nor CsvHelper.CsvWriter.Context or somewhere else.
As an acceptable for me workaround I tried to override method ConvertUsing of class MemberMap<TClass, TMember> and it didn't work correctly:
public class CustomMemberMap < TClass, TMember >: MemberMap < TClass, TMember > {
public CustomMemberMap(MemberInfo member): base(member) {}
public override MemberMap < TClass, TMember > ConvertUsing(Func < TClass, string > convertExpression) => base.ConvertUsing(row => convertExpression(row).Replace("\r", "").Replace("\n", ""));
}
public class CustomClassMap < TClass >: ClassMap < TClass > where TClass: new() {
public override MemberMap < TClass, TMember > Map < TMember > (Expression < Func < TClass, TMember >> expression, bool useExistingMap = true) => new CustomMemberMap < TClass, TMember > (base.Map(expression, useExistingMap).Data.Member);
}
public sealed class CsvFileMapperAccommodation: CustomClassMap < Accommodation > {
public CsvFileMapperAccommodation() {
Map(m => m.Name).Name($ "AccommodationName").ConvertUsing(x => $ "{x.Name}");
Map(m => m.ExternalKey).Name($ "AccommodationExternalKey").ConvertUsing(x => $ "{x.ExternalKey}");
Map(m => m.Pension).Name($ "AccommodationPension").ConvertUsing(x => $ "{x.Pension}");
Map(m => m.Category).Name($ "AccommodationCategory").ConvertUsing(x => $ "{x.Category}");
Map(m => m.BuyingPrice).Name($ "AccommodationBuyingPrice").ConvertUsing(x => $ "{x.BuyingPrice}");
Map(m => m.Margin).Name($ "AccommodationMargin").ConvertUsing(x => $ "{x.Margin}");
Map(m => m.Price).Name($ "AccommodationPrice").ConvertUsing(x => $ "{x.Price}");
Map(m => m.Quantity).Name($ "AccommodationQuantity").ConvertUsing(x => $ "{x.Quantity}");
Map(m => m.Supplier).Name($ "AccommodationSupplier").ConvertUsing(x => $ "{x.Supplier}");
}
}
The object (which I try to map) contains a lot of properties so in an output I have about 300 fields per row, therefore, it's too complicated and not elegant to change manually the object data in the beginning and the value for each of the fields in the end. So I only try to map this object into a csv string hoping that it's possible to change it on the fly.

I think creating a custom StringConverter might meet your needs.
public class Program
{
public static void Main(string[] args)
{
var records = new List<Foo>()
{
new Foo {Property1 = "Property 1 with \r\n \\r\\n", Property2 = "Property2 with \n \\n"}
};
using (var csv = new CsvWriter(Console.Out, CultureInfo.InvariantCulture))
{
csv.Configuration.TypeConverterCache.AddConverter<string>(new FooStringConverter());
csv.WriteRecords(records);
}
Console.ReadKey();
}
}
public class Foo
{
public string Property1 { get; set; }
public string Property2 { get; set; }
}
public class FooStringConverter: StringConverter
{
public override string ConvertToString(object value, IWriterRow row, MemberMapData memberMapData)
{
var stringValue = (string)value;
if (stringValue != null)
{
stringValue = stringValue.Replace("\r", "").Replace("\n", "");
}
return base.ConvertToString(stringValue, row, memberMapData);
}
}

Related

Get dependent ids when querying principal

I'm trying to get just the ids for dependents if a principal is queried, every time the principal is queried.
My initial thought is to add it somehow in the OnModelCreating definitions, however that appears to be limited to filtering down larger sets of data, unless I'm missing something.
Something like this:
builder.Entity<ListingModel>()
.AlsoDoThis(
x => x.MenuIds.AddRange(
Menus.Where(y => y.ListingId == x.Id).Select(y => y.Id).ToList()
)
);
There is a need to not do this in code for each individual place I have a Select, since that functionality is normalized in some base classes. The base classes have a <TModel> passed in and don't inherently know what properties need to be handled this way.
I do have a workaround where I'm grabbing everything with an AutoInclude(), then filtering it out in the model definition with customer getter/setter to return a list of ids. But rather than being more performant (grabbing related FK ids at the DB level) it's transferring all of that data to the server and then programmatically selecting a list of ids, as far as I understand it.
private List<int> _topicsIds = new();
[NotMapped]
public List<int> TopicsIds
{
get { return Topics.Count > 0 ? Topics.Select(x => x.Id).ToList() : _topicsIds; }
set { _topicsIds = value; }
}
public List<TopicModel> Topics { get; set; } = new();
"Extra SQL that gets called with every select in a context" is (to my limited knowledge) almost what HasQueryFilter does, with a just slightly broader operation. I think this is the approach I'm looking for, just selecting more stuff instead of filtering stuff out.
You can project everything via Select
var result = ctx.ListingModels
.Select(lm => new // or to DTO
{
Id = lm.Id,
OtherProperty = lm.OtherProperty,
Ids = x.MenuIds.Select(m => m.Id).ToList()
})
.ToList();
To make more general solution we can use annotations and define how to project such entities.
During Model defining:
builder.Entity<TopicModel>()
.WithProjection(
x => x.MenuIds,
x => x.Menus.Where(y => y.ListingId == x.Id).Select(y => y.Id).ToList()
);
Then usage in common code:
public virtual List<TModel> GetList(List<int> ids)
{
var list = _context.Set<TModel>().Where(x => ids.Any(id => id == x.Id))
.ApplyCustomProjection(_context)
.ToList();
return list;
}
ApplyCustomProjection(_context) will find previously defined annotation and will apply custom projection.
And extensions implementation:
public static class ProjectionExtensions
{
public const string CustomProjectionAnnotation = "custom:member_projection";
public class ProjectionInfo
{
public ProjectionInfo(MemberInfo member, LambdaExpression expression)
{
Member = member;
Expression = expression;
}
public MemberInfo Member { get; }
public LambdaExpression Expression { get; }
}
public static bool IsUnderDotnetTool { get; }
= Process.GetCurrentProcess().ProcessName == "dotnet";
public static EntityTypeBuilder<TEntity> WithProjection<TEntity, TValue>(
this EntityTypeBuilder<TEntity> entity,
Expression<Func<TEntity, TValue>> propExpression,
Expression<Func<TEntity, TValue>> assignmentExpression)
where TEntity : class
{
// avoid registering non serializable annotations during migrations update
if (IsUnderDotnetTool)
return entity;
var annotation = entity.Metadata.FindAnnotation(CustomProjectionAnnotation);
var projections = annotation?.Value as List<ProjectionInfo> ?? new List<ProjectionInfo>();
if (propExpression.Body is not MemberExpression memberExpression)
throw new InvalidOperationException($"'{propExpression.Body}' is not member expression");
if (memberExpression.Expression is not ParameterExpression)
throw new InvalidOperationException($"'{memberExpression.Expression}' is not parameter expression. Only single nesting is allowed");
// removing duplicate
projections.RemoveAll(p => p.Member == memberExpression.Member);
projections.Add(new ProjectionInfo(memberExpression.Member, assignmentExpression));
return entity.HasAnnotation(CustomProjectionAnnotation, projections);
}
public static IQueryable<TEntity> ApplyCustomProjection<TEntity>(this IQueryable<TEntity> query, DbContext context)
where TEntity : class
{
var et = context.Model.FindEntityType(typeof(TEntity));
var projections = et?.FindAnnotation(CustomProjectionAnnotation)?.Value as List<ProjectionInfo>;
// nothing to do
if (projections == null || et == null)
return query;
var propertiesForProjection = et.GetProperties().Where(p =>
p.PropertyInfo != null && projections.All(pr => pr.Member != p.PropertyInfo))
.ToList();
var entityParam = Expression.Parameter(typeof(TEntity), "e");
var memberBinding = new MemberBinding[propertiesForProjection.Count + projections.Count];
for (int i = 0; i < propertiesForProjection.Count; i++)
{
var propertyInfo = propertiesForProjection[i].PropertyInfo!;
memberBinding[i] = Expression.Bind(propertyInfo, Expression.MakeMemberAccess(entityParam, propertyInfo));
}
for (int i = 0; i < projections.Count; i++)
{
var projection = projections[i];
var expression = projection.Expression.Body;
var assignExpression = ReplacingExpressionVisitor.Replace(projection.Expression.Parameters[0], entityParam, expression);
memberBinding[propertiesForProjection.Count + i] = Expression.Bind(projection.Member, assignExpression);
}
var memberInit = Expression.MemberInit(Expression.New(typeof(TEntity)), memberBinding);
var selectLambda = Expression.Lambda<Func<TEntity, TEntity>>(memberInit, entityParam);
var newQuery = query.Select(selectLambda);
return newQuery;
}
}

Subscribe to Close, but close only if item was saved

My scenario:
In an MVVM pattern, the view should be closed when a command is executed on ViewModel, but only if the item was successfully saved.
The View looks like:
public class CentreUpdateWindow : ReactiveWindow<CentreUpdateViewModel>
{
public CentreUpdateWindow()
{
this.InitializeComponent();
this.WhenActivated(d =>
d(ViewModel!.SubmitCommand.Subscribe(CloseIfSuccessfullySaved))
);
}
private void CloseIfSaved(Centre? obj)
{
if (ViewModel!.SuccessfullySaved)
Close(obj);
}
// ...
And the ViewModel:
public class CentreUpdateViewModel : ViewModelBase, IId
{
// ...
public ReactiveCommand<Unit, dtoo.Centre?> SubmitCommand { get; }
private bool _SuccessfullySaved;
public bool SuccessfullySaved
{
get { return _SuccessfullySaved; }
protected set { this.RaiseAndSetIfChanged(ref _SuccessfullySaved, value); }
}
The question:
The code works fine, but I'm not comfortable with the if (ViewModel!.SuccessfullySaved). I guess should be a way to write subscribe expression more accurate.
Is there a more elegant way to Subscribe on WhenActivated more "reactiveuistic" ?
public CentreUpdateWindow()
{
this.InitializeComponent();
this.WhenActivated(d =>
d(
ViewModel
.WhenAnyValue(x => x.SuccessfullySaved)
.CombineLatest(ViewModel!.SubmitCommand,
(saved, obj) => (saved, obj))
.Where(s => s.saved)
.Select(s => s.obj)
.Subscribe(Close)
));
}

How could I create a sub type of `I` that would wrap other sub types of `I`?

Given the following in Java:
public interface Reply<T> {
T data();
}
public class StatusReply implements Reply<String> {
private final String status;
public StatusReply(String status) {
this.status = status;
}
#Override
public String data() {
return status;
}
}
I want to be able to do this in Scala:
class PassthroughReply[R <: Reply[_]](val reply: R)
extends Reply[T] { // won't compile, `T` type not found
override
def data[T : Reply]: T = reply.data
}
val statusReply = new StatusReply("OK")
val passthroughReply = new PassthroughReply[SatusReply](statusReply)
passthroughReply.data // Should return "OK"
What I want is that the data in an instance of PassthroughReply, should have the same type as the data of its wrapped sub type of Reply.
How about this?
class PassthroughReply[T](val reply: Reply[T]) extends Reply[T] {
override def data = reply.data
}

How to pass a parameter to a named services in LightInject?

In LightInject,registering a named service goes a s follows:
container.Register<IFoo, Foo>();
container.Register<IFoo, AnotherFoo>("AnotherFoo");
var instance = container.GetInstance<IFoo>("AnotherFoo");
A service with a parameter:
container.Register<int, IFoo>((factory, value) => new Foo(value));
var fooFactory = container.GetInstance<Func<int, IFoo>>();
var foo = (Foo)fooFactory(42);
How to combine these two together, to have a named service with a parameter passed to a constructor?
You mean like this?
class Program
{
static void Main(string[] args)
{
var container = new ServiceContainer();
container.Register<string,IFoo>((factory, s) => new Foo(s), "Foo");
container.Register<string, IFoo>((factory, s) => new AnotherFoo(s), "AnotherFoo");
var foo = container.GetInstance<string, IFoo>("SomeValue", "Foo");
Debug.Assert(foo.GetType().IsAssignableFrom(typeof(Foo)));
var anotherFoo = container.GetInstance<string, IFoo>("SomeValue", "AnotherFoo");
Debug.Assert(anotherFoo.GetType().IsAssignableFrom(typeof(AnotherFoo)));
}
}
public interface IFoo { }
public class Foo : IFoo
{
public Foo(string value){}
}
public class AnotherFoo : IFoo
{
public AnotherFoo(string value) { }
}

Autofac PropertiesAutowired - Is it possible to ignore a one or more properties?

Despite the advice to pass dependencies through the constructor I've found that the development cost of having parameterless constructors and then autowiring all of the properties on everything is significantly less and makes the application much easier to develop out and maintain. However sometimes (on a view model for example) I have a property that is registered with the container, but that I don't want to populate at construction (for example the selected item bound to a container).
Is there any way to tell the container to ignore certain properties when it autowires the rest?
At the moment I'm just resetting the properties marked with an attribute in the on activated event a la:
public static IRegistrationBuilder<TLimit, ScanningActivatorData, TRegistrationStyle>
PropertiesAutowiredExtended<TLimit, TRegistrationStyle>(
this IRegistrationBuilder<TLimit, ScanningActivatorData, TRegistrationStyle> builder)
{
builder.ActivatorData.ConfigurationActions.Add(
(type, innerBuilder) =>
{
var parameter = Expression.Parameter(typeof(object));
var cast = Expression.Convert(parameter, type);
var assignments = type.GetProperties()
.Where(candidate => candidate.HasAttribute<NotAutowiredAttribute>())
.Select(property => new { Property = property, Expression = Expression.Property(cast, property) })
.Select(data => Expression.Assign(data.Expression, Expression.Default(data.Property.PropertyType)))
.Cast<Expression>()
.ToArray();
if (assignments.Any())
{
var #action = Expression
.Lambda<Action<object>>(Expression.Block(assignments), parameter)
.Compile();
innerBuilder.OnActivated(e =>
{
e.Context.InjectUnsetProperties(e.Instance);
#action(e.Instance);
});
}
else
{
innerBuilder.OnActivated(e => e.Context.InjectUnsetProperties(e.Instance));
}
});
return builder;
}
Is there a better way to do this?
Not sure that this is a better one, but you can go from another side, register only needed properties via WithProperty syntax. Pros is that Autofac doesn't resolve unnecessary services. Here's a working example:
public class MyClass
{
public MyDependency MyDependency { get; set; }
public MyDependency MyExcludeDependency { get; set; }
}
public class MyDependency {}
public class Program
{
public static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType<MyDependency>();
builder.RegisterType<MyClass>().WithPropertiesAutowiredExcept("MyExcludeDependency");
using (var container = builder.Build())
{
var myClass = container.Resolve<MyClass>();
Console.WriteLine(myClass.MyDependency == null);
Console.WriteLine(myClass.MyExcludeDependency == null);
}
}
}
public static class PropertiesAutowiredExtensions
{
// Extension that registers only needed properties
// Filters by property name for simplicity
public static IRegistrationBuilder<TLimit, TReflectionActivatorData, TRegistrationStyle>
WithPropertiesAutowiredExcept<TLimit, TReflectionActivatorData, TRegistrationStyle>(
this IRegistrationBuilder<TLimit, TReflectionActivatorData, TRegistrationStyle> registrationBuilder,
params string[] propertiesNames)
where TReflectionActivatorData : ReflectionActivatorData
{
var type = ((IServiceWithType)registrationBuilder.RegistrationData.Services.Single()).ServiceType;
foreach (var property in type
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(pi => pi.CanWrite && !propertiesNames.Contains(pi.Name)))
{
// There's no additional checks like in PropertiesAutowired for simplicity
// You can add them from Autofac.Core.Activators.Reflection.AutowiringPropertyInjector.InjectProperties
var localProperty = property;
registrationBuilder.WithProperty(
new ResolvedParameter(
(pi, c) =>
{
PropertyInfo prop;
return pi.TryGetDeclaringProperty(out prop) &&
prop.Name == localProperty.Name;
},
(pi, c) => c.Resolve(localProperty.PropertyType)));
}
return registrationBuilder;
}
// From Autofac.Util.ReflectionExtensions
public static bool TryGetDeclaringProperty(this ParameterInfo pi, out PropertyInfo prop)
{
var mi = pi.Member as MethodInfo;
if (mi != null && mi.IsSpecialName && mi.Name.StartsWith("set_", StringComparison.Ordinal)
&& mi.DeclaringType != null)
{
prop = mi.DeclaringType.GetProperty(mi.Name.Substring(4));
return true;
}
prop = null;
return false;
}
}