public DocumentDesigner <TEntity> With <TMember, TReturn>(string name, Expression <Func <TEntity, TMember> > projector, Func <TMember, TReturn> converter, params Option[] options) { if (typeof(TReturn) == typeof(string)) { options = options.Concat(new MaxLength(850)).ToArray(); } var column = design.Table[name]; if (DocumentTable.IdColumn.Equals(column)) { throw new ArgumentException("You can not make a projection for IdColumn. Use Document.Key() method instead."); } if (column == null) { var lengthOption = options .OfType <MaxLength>() .FirstOrDefault(); column = design.Table.Add(new Column <TReturn>(name, lengthOption?.Length)); } Func <object, object> compiledProjector; if (!options.OfType <DisableNullCheckInjection>().Any()) { var nullCheckInjector = new NullCheckInjector(); var nullCheckedProjector = (Expression <Func <TEntity, object> >)nullCheckInjector.Visit(projector); if (!nullCheckInjector.CanBeTrustedToNeverReturnNull && !column.IsPrimaryKey) { column.Nullable = true; } compiledProjector = Compile(name, nullCheckedProjector); } else { compiledProjector = Compile(name, projector); } var newProjection = Projection.From <TReturn>(document => { var value = compiledProjector(document); if (value == null) { return(null); } return(converter((TMember)value)); }); if (!newProjection.ReturnType.IsCastableTo(column.Type)) { throw new InvalidOperationException( $"Can not override projection for {name} of type {column.Type} " + $"with a projection that returns {newProjection.ReturnType} (on {typeof (TEntity)})."); } Projection existingProjection; if (!design.Projections.TryGetValue(name, out existingProjection)) { if (design.Parent != null && !column.IsPrimaryKey) { column.Nullable = true; } design.Projections.Add(column, newProjection); } else { design.Projections[name] = newProjection; } return(this); }