Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions NoRM.Tests/MongoCollectionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -382,8 +382,86 @@ public void InsertingANewEntityWithNullableIntGeneratesAKey()
Assert.NotNull(testint._id);
Assert.AreNotEqual(0, testint._id.Value);
}
}



[Test]
public void when_inserting_a_new_entity_with_int_id_equals_zero_generates_a_key()
{
using (var mongo = Mongo.Create(TestHelper.ConnectionString()))
{
var testint = new IntId {Name = "first"} ;
mongo.GetCollection<IntId>("Fake").Insert(testint);

Assert.NotNull(testint.Id);
Assert.AreNotEqual(0, testint.Id);
}
}

[Test]
public void when_inserting_a_22_new_entities_with_int_id_equals_zero_generates_a_unique_key_for_each_of_them()
{
using (var mongo = Mongo.Create(TestHelper.ConnectionString()))
{
var idents = new List<int>();
for (int i = 0; i <22; i++)
{
var testint = new IntId() ;
mongo.GetCollection<IntId>("Fake").Insert(testint);
idents.Add(testint.Id);
}

var list = mongo.GetCollection<IntId>("Fake").Find(new { _id = Q.In(idents.ToArray()) });

foreach (var item in list)
{
Assert.True(idents.Contains(item.Id));
}

Assert.AreEqual(idents.Distinct().Count(), list.Select(x => x.Id).Distinct().Count());
}
}


[Test]
public void when_inserting_a_new_entity_with_long_type_id_equals_zero_generates_a_key()
{
using (var mongo = Mongo.Create(TestHelper.ConnectionString()))
{
var testint = new LongId() { Name = "first" };
mongo.GetCollection<LongId>("Fake").Insert(testint);

Assert.NotNull(testint.Id);
Assert.AreNotEqual(0, testint.Id);
}
}

[Test]
public void when_inserting_a_22_new_entities_with_long_type_id_equals_zero_generates_a_unique_key_for_each_of_them()
{
using (var mongo = Mongo.Create(TestHelper.ConnectionString()))
{
var idents = new List<long>();
for (int i = 0; i < 22; i++)
{
var testint = new LongId();
mongo.GetCollection<LongId>("Fake").Insert(testint);
idents.Add(testint.Id);
}

var list = mongo.GetCollection<LongId>("Fake").Find(new { _id = Q.In(idents.ToArray()) });

foreach (var item in list)
{
Assert.True(idents.Contains(item.Id));
}

Assert.AreEqual(idents.Distinct().Count(), list.Select(x => x.Id).Distinct().Count());
}
}


[Test]
public void InsertingANewEntityWithNullableIntGeneratesAKeyComplex()
{
Expand Down Expand Up @@ -520,6 +598,8 @@ public void StringAsIdentifierDoesTranslation()
}
}



private class StringIdentifier
{
[MongoIdentifier]
Expand All @@ -531,6 +611,12 @@ private class IntId
{
public int Id { get; set; }
public string Name { get; set; }
}

private class LongId
{
public long Id { get; set; }
public string Name { get; set; }
}
}
}
38 changes: 36 additions & 2 deletions NoRM.Tests/MongoConfigurationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -224,8 +224,42 @@ public void Are_Queries_Fully_Linqified()
Assert.AreEqual("Cart1", deepQuery[0].Cart.Name);
Assert.AreEqual(1, deepQuery.Count);
}
}

}

[Test]
public void should_ignore_name_property_when_inserting__as_specified_in_mappings()
{

MongoConfiguration.Initialize(c => c.AddMap<ShopperMapWithIgnoreImmutableAndIgnoreIfNullConfigurationForProperties>());
using (
Shoppers shoppers =
new Shoppers(Mongo.Create(TestHelper.ConnectionString("pooling=false", "test", null, null))))
{
shoppers.Drop<Shopper>();
shoppers.Add(new Shopper
{
Id = ObjectId.NewObjectId(),
Name = "John",

});

shoppers.Add(new Shopper
{
Id = ObjectId.NewObjectId(),
Name = "Jane",

});


var deepQuery = shoppers.ToList();

Assert.IsNull(deepQuery[0].Name);
Assert.IsNull(deepQuery[1].Name);


}
}

[Test]
public void Can_correctly_determine_collection_name()
{
Expand Down
19 changes: 19 additions & 0 deletions NoRM.Tests/TestClasses.cs
Original file line number Diff line number Diff line change
Expand Up @@ -879,6 +879,25 @@ public ShopperMap()
}
}

public class ShopperMapWithIgnoreImmutableAndIgnoreIfNullConfigurationForProperties:MongoConfigurationMap
{
public ShopperMapWithIgnoreImmutableAndIgnoreIfNullConfigurationForProperties()
{
For<Shopper>(
config=> config.ForProperty(x => x.Name).Ignore()
);

For<Cart>(
config=>
{

config.ForProperty(x => x.Product).IgnoreIfNull();
config.ForProperty(x => x.Name).Immutable();

}
);
}
}
internal class IdMap0
{
public ObjectId _ID { get; set; }
Expand Down
12 changes: 8 additions & 4 deletions NoRM/BSON/MagicProperty.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
using System;
using System.Reflection;
using Norm.Attributes;
using System.ComponentModel;

using System.ComponentModel;
using Norm.Configuration;

namespace Norm.BSON
{
/// <summary>
Expand All @@ -27,8 +28,11 @@ public class MagicProperty
public MagicProperty(PropertyInfo property, Type declaringType)
{
_property = property;
this.IgnoreIfNull = property.GetCustomAttributes(_ignoredIfNullType, true).Length > 0;
this.Immutable = property.GetCustomAttributes(_immutableType, true).Length > 0;
this.IgnoreIfNull = property.GetCustomAttributes(_ignoredIfNullType, true).Length > 0 ||
MongoConfiguration.IsPropertyIgnoredWhenNull(declaringType,property.Name);
this.Immutable = property.GetCustomAttributes(_immutableType, true).Length > 0 ||
MongoConfiguration.IsPropertyImmutable(declaringType,property.Name);

var props = property.GetCustomAttributes(_defaultValueType, true);
if (props.Length > 0)
{
Expand Down
3 changes: 2 additions & 1 deletion NoRM/BSON/ReflectionHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,8 @@ private static IDictionary<string, MagicProperty> LoadMagicProperties(IEnumerabl
foreach (var property in properties)
{
if (property.GetCustomAttributes(_ignoredType, true).Length > 0 ||
property.GetIndexParameters().Length > 0)
property.GetIndexParameters().Length > 0||
MongoConfiguration.IsPropertyIgnored(property.DeclaringType,property.Name))
{
continue;
}
Expand Down
75 changes: 75 additions & 0 deletions NoRM/Collections/CreateIndexExpression.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
using System;
using System.Linq.Expressions;
using Norm.BSON;
using Norm.Configuration;
using Norm.Protocol.Messages;

namespace Norm.Collections
{
class CreateIndexExpression<T> : ICreateIndexExpression<T>
{
public Expando Expando
{
get;
set;
}

public string CompoundName
{
get;
set;
}

public CreateIndexExpression()
{
Expando = new Expando();

}
public void Index(Expression<Func<T, object>> func, IndexOption indexDirection)
{
var propName = this.RecurseExpression(func.Body);
Expando[propName] = indexDirection;
CompoundName += propName + "_" + (int)indexDirection;

}
private String RecurseExpression(Expression body)
{
var me = body as MemberExpression;
if (me != null)
{
return this.RecurseMemberExpression(me);
}

var ue = body as UnaryExpression;
if (ue != null)
{
return this.RecurseExpression(ue.Operand);
}

throw new MongoException("Unknown expression type, expected a MemberExpression or UnaryExpression.");
}
private String RecurseMemberExpression(MemberExpression mex)
{
var retval = "";
var parentEx = mex.Expression as MemberExpression;
if (parentEx != null)
{
//we need to recurse because we're not at the root yet.
retval += this.RecurseMemberExpression(parentEx) + ".";
}
retval += MongoConfiguration.GetPropertyAlias(mex.Expression.Type, mex.Member.Name);
return retval;
}

}

public interface ICreateIndexExpression<T>
{
// Methods
void Index(Expression<Func<T, object>> func, IndexOption indexDirection);

// Properties
string CompoundName { get; set; }
Expando Expando { get; set; }
}
}
37 changes: 31 additions & 6 deletions NoRM/Collections/MongoCollectionGeneric.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public IQueryable<T> AsQueryable()
/// <summary>
/// True if the type of this collection can be updated
/// (i.e. the Type specifies "_id", "ID", or a property with the attributed "MongoIdentifier").
/// </summary>
/// </summary>|?/**/
public bool Updateable
{
get
Expand Down Expand Up @@ -106,11 +106,18 @@ public void Save(T entity)
var helper = TypeHelper.GetHelperForType(typeof(T));
var idProperty = helper.FindIdProperty();
var id = idProperty.Getter(entity);
if (id == null &&
(typeof(ObjectId).IsAssignableFrom(idProperty.Type)) ||
if ((id == null &&
((typeof(ObjectId).IsAssignableFrom(idProperty.Type)) ||
(typeof(long?).IsAssignableFrom(idProperty.Type)) ||
(typeof(int?).IsAssignableFrom(idProperty.Type)) )
(typeof(int?).IsAssignableFrom(idProperty.Type)))) ||

(idProperty.Type == typeof(int) && id.Equals(0)) ||
(idProperty.Type == typeof(long) && id.Equals((long)0))

)
{


Insert(entity);
}
else
Expand Down Expand Up @@ -545,7 +552,19 @@ public void CreateGeoIndex<U>(Expression<Func<T, U>> index, IEnumerable<MongoCol
this.CreateIndex(key, indexName, isUnique);
}
// else throw Exception? (Only 1 key can be used for geospatial index)
}
}




public void CreateCompoundIndex(Action<ICreateIndexExpression<T>> indexes, bool isUnique)
{
ICreateIndexExpression<T> expression = new CreateIndexExpression<T>();
indexes(expression);

this.CreateIndex(expression.Expando, expression.CompoundName, isUnique);

}

/// <summary>
/// Gets the distinct values for the specified fieldSelectionExpando.
Expand Down Expand Up @@ -879,19 +898,25 @@ private void TrySettingId(IEnumerable<T> entities)
Dictionary<Type, Func<object>> knownTypes = new Dictionary<Type, Func<object>> {
{ typeof(long?), () => GenerateId() },
{ typeof(int?), () => Convert.ToInt32(GenerateId()) },
{ typeof(int), () => Convert.ToInt32(GenerateId()) },
{ typeof(long), () => GenerateId() },
{ typeof(ObjectId), () => ObjectId.NewObjectId() }
};

if (typeof(T) != typeof(Object) && typeof(T).GetInterface("IUpdateWithoutId") == null)
{
var idProperty = TypeHelper.GetHelperForType(typeof(T)).FindIdProperty();

if (idProperty != null && knownTypes.ContainsKey(idProperty.Type) && idProperty.Setter != null)
{
foreach (var entity in entities)
{
var value = idProperty.Getter(entity);
if (value == null)
if (value == null ||
(idProperty.Type==typeof(int) && value.Equals(0) )||
idProperty.Type==typeof(long) && value.Equals((long)0))
{

idProperty.Setter(entity, knownTypes[idProperty.Type]());
}
}
Expand Down
9 changes: 8 additions & 1 deletion NoRM/Configuration/IMongoConfigurationMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,14 @@ public interface IMongoConfigurationMap : IHideObjectMembers
/// <returns>
/// Type's property alias if configured; otherwise null
/// </returns>
string GetPropertyAlias(Type type, string propertyName);
string GetPropertyAlias(Type type, string propertyName);

bool IsPropertyIgnored(Type type, string propertyName);

bool IsPropertyIgnoredWhenNull(Type type, string propertyName);

bool IsPropertyImmutable(Type type, string propertyName);


string GetTypeDescriminator(Type type);
}
Expand Down
Loading