mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-03-01 15:29:11 +00:00
HHH-7052 : Bind PluralAttributeKeyBinding
This commit is contained in:
parent
8afab9f255
commit
f839cd22ef
@ -52,6 +52,7 @@
|
||||
import org.hibernate.metamodel.spi.binding.CompositeAttributeBinding;
|
||||
import org.hibernate.metamodel.spi.binding.EntityBinding;
|
||||
import org.hibernate.metamodel.spi.binding.EntityDiscriminator;
|
||||
import org.hibernate.metamodel.spi.binding.HibernateTypeDescriptor;
|
||||
import org.hibernate.metamodel.spi.binding.IdGenerator;
|
||||
import org.hibernate.metamodel.spi.binding.InheritanceType;
|
||||
import org.hibernate.metamodel.spi.binding.ManyToOneAttributeBinding;
|
||||
@ -95,6 +96,7 @@
|
||||
import org.hibernate.metamodel.spi.source.MetadataImplementor;
|
||||
import org.hibernate.metamodel.spi.source.Orderable;
|
||||
import org.hibernate.metamodel.spi.source.PluralAttributeElementSource;
|
||||
import org.hibernate.metamodel.spi.source.PluralAttributeKeySource;
|
||||
import org.hibernate.metamodel.spi.source.PluralAttributeNature;
|
||||
import org.hibernate.metamodel.spi.source.PluralAttributeSource;
|
||||
import org.hibernate.metamodel.spi.source.PrimaryKeyJoinColumnSource;
|
||||
@ -261,7 +263,9 @@ private EntityBinding doCreateEntityBinding(EntitySource entitySource, EntityBin
|
||||
final EntityBinding entityBinding = createBasicEntityBinding( entitySource, superEntityBinding );
|
||||
|
||||
bindSecondaryTables( entitySource, entityBinding );
|
||||
|
||||
Deque<TableSpecification> tableStack = new ArrayDeque<TableSpecification>( );
|
||||
tableStack.add( entityBinding.getPrimaryTable() );
|
||||
bindAttributes( entitySource, entityBinding, tableStack );
|
||||
|
||||
bindTableUniqueConstraints( entitySource, entityBinding );
|
||||
@ -614,7 +618,10 @@ else if ( attributeSource.isVirtualAttribute() ) {
|
||||
final List<RelationalValueBinding> relationalValueBindings = createSimpleRelationalValues(
|
||||
attributeSource,
|
||||
attributeBindingContainer,
|
||||
attribute
|
||||
attribute,
|
||||
attributeBindingContainer
|
||||
.seekEntityBinding()
|
||||
.getPrimaryTable()
|
||||
);
|
||||
final String propertyAccessorName = Helper.getPropertyAccessorName(
|
||||
attributeSource.getPropertyAccessorName(),
|
||||
@ -794,7 +801,10 @@ else if ( attributeSource.isVirtualAttribute() ) {
|
||||
final List<RelationalValueBinding> relationalValueBindings = createSimpleRelationalValues(
|
||||
attributeSource,
|
||||
attributeBindingContainer,
|
||||
attribute
|
||||
attribute,
|
||||
attributeBindingContainer
|
||||
.seekEntityBinding()
|
||||
.getPrimaryTable()
|
||||
);
|
||||
final String propertyAccessorName = Helper.getPropertyAccessorName(
|
||||
attributeSource.getPropertyAccessorName(),
|
||||
@ -955,6 +965,8 @@ private void doBasicPluralAttributeBinding(PluralAttributeSource source, Abstrac
|
||||
binding.setCustomSqlDelete( source.getCustomSqlDelete() );
|
||||
binding.setCustomSqlDeleteAll( source.getCustomSqlDeleteAll() );
|
||||
|
||||
binding.setWhere( source.getWhere() );
|
||||
|
||||
// doBasicAttributeBinding( source, binding );
|
||||
}
|
||||
|
||||
@ -1020,8 +1032,6 @@ public String inferredTableName() {
|
||||
if ( StringHelper.isNotEmpty( attributeSource.getCollectionTableCheck() ) ) {
|
||||
pluralAttributeBinding.getCollectionTable().addCheckConstraint( attributeSource.getCollectionTableCheck() );
|
||||
}
|
||||
|
||||
pluralAttributeBinding.setWhere( attributeSource.getWhere() );
|
||||
}
|
||||
|
||||
private void bindCollectionKey(
|
||||
@ -1029,56 +1039,91 @@ private void bindCollectionKey(
|
||||
AbstractPluralAttributeBinding pluralAttributeBinding,
|
||||
Deque<TableSpecification> tableStack) {
|
||||
|
||||
// TableSpecification targetTable = tableStack.peekLast();
|
||||
pluralAttributeBinding.getPluralAttributeKeyBinding().prepareForeignKey(
|
||||
attributeSource.getKeySource().getExplicitForeignKeyName(),
|
||||
//tableStack.peekLast().getLogicalName()
|
||||
null // todo : handle secondary table names
|
||||
final PluralAttributeKeySource keySource = attributeSource.getKeySource();
|
||||
|
||||
String foreignKeyName = (
|
||||
StringHelper.isNotEmpty( keySource.getExplicitForeignKeyName() ) ?
|
||||
quoteIdentifier( keySource.getExplicitForeignKeyName() ) :
|
||||
null // TODO: is null FK name allowd (is there a default?)
|
||||
);
|
||||
pluralAttributeBinding.getPluralAttributeKeyBinding().getForeignKey().setDeleteRule(
|
||||
attributeSource.getKeySource().getOnDeleteAction()
|
||||
pluralAttributeBinding.getPluralAttributeKeyBinding().prepareForeignKey(
|
||||
foreignKeyName,
|
||||
tableStack.peekLast()
|
||||
);
|
||||
final ForeignKey foreignKey = pluralAttributeBinding.getPluralAttributeKeyBinding().getForeignKey();
|
||||
|
||||
Iterator<RelationalValueBinding> targetValueBindings = null;
|
||||
if ( attributeSource.getKeySource().getReferencedEntityAttributeName() != null ) {
|
||||
final EntityBinding ownerEntityBinding = pluralAttributeBinding.getContainer().seekEntityBinding();
|
||||
final AttributeBinding referencedAttributeBinding = ownerEntityBinding.locateAttributeBinding(
|
||||
attributeSource.getKeySource().getReferencedEntityAttributeName()
|
||||
foreignKey.setDeleteRule( keySource.getOnDeleteAction() );
|
||||
|
||||
if ( keySource.getReferencedEntityAttributeName() == null ) {
|
||||
bindCollectionKeyTargetingPrimaryKey( attributeSource.getKeySource(), pluralAttributeBinding );
|
||||
}
|
||||
else {
|
||||
bindCollectionKeyTargetingPropertyRef( attributeSource.getKeySource(), pluralAttributeBinding );
|
||||
}
|
||||
|
||||
HibernateTypeDescriptor targetTypeDescriptor = pluralAttributeBinding.getHibernateTypeDescriptor();
|
||||
|
||||
}
|
||||
|
||||
private void bindCollectionKeyTargetingPrimaryKey(
|
||||
PluralAttributeKeySource keySource,
|
||||
AbstractPluralAttributeBinding pluralAttributeBinding) {
|
||||
|
||||
for ( RelationalValueSource valueSource : keySource.getValueSources() ) {
|
||||
if ( ColumnSource.class.isInstance( valueSource ) ) {
|
||||
final Column column = makeColumn(
|
||||
ColumnSource.class.cast( valueSource ),
|
||||
COLL_KEY_COLUMN_BINDING_DEFAULTS,
|
||||
pluralAttributeBinding.getCollectionTable(),
|
||||
pluralAttributeBinding.getAttribute().getName(),
|
||||
true
|
||||
);
|
||||
pluralAttributeBinding.getPluralAttributeKeyBinding().getForeignKey().addColumn( column );
|
||||
}
|
||||
else {
|
||||
// TODO: deal with formulas???
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void bindCollectionKeyTargetingPropertyRef(
|
||||
PluralAttributeKeySource keySource,
|
||||
AbstractPluralAttributeBinding pluralAttributeBinding) {
|
||||
final EntityBinding ownerEntityBinding = pluralAttributeBinding.getContainer().seekEntityBinding();
|
||||
final AttributeBinding referencedAttributeBinding = ownerEntityBinding.locateAttributeBinding(
|
||||
keySource.getReferencedEntityAttributeName()
|
||||
);
|
||||
final ForeignKey foreignKey = pluralAttributeBinding.getPluralAttributeKeyBinding().getForeignKey();
|
||||
if ( ! referencedAttributeBinding.getAttribute().isSingular() ) {
|
||||
throw new MappingException(
|
||||
String.format(
|
||||
"Collection (%s) property-ref is a plural attribute (%s); must be singular.",
|
||||
pluralAttributeBinding.getAttribute().getRole(),
|
||||
referencedAttributeBinding
|
||||
),
|
||||
currentBindingContext.getOrigin()
|
||||
);
|
||||
if ( ! referencedAttributeBinding.getAttribute().isSingular() ) {
|
||||
}
|
||||
Iterator<RelationalValueBinding> targetValueBindings =
|
||||
( (SingularAttributeBinding) referencedAttributeBinding ).getRelationalValueBindings().iterator();
|
||||
for ( RelationalValueSource valueSource : keySource.getValueSources() ) {
|
||||
if ( ! targetValueBindings.hasNext() ) {
|
||||
throw new MappingException(
|
||||
String.format(
|
||||
"Collection (%s) property-ref is a plural attribute (%s); must be singular.",
|
||||
pluralAttributeBinding.getAttribute().getRole(),
|
||||
referencedAttributeBinding
|
||||
"More collection key source columns than target columns for collection: %s",
|
||||
pluralAttributeBinding.getAttribute().getRole()
|
||||
),
|
||||
currentBindingContext.getOrigin()
|
||||
);
|
||||
}
|
||||
// targetValueBindings = ( (SingularAttributeBinding) referencedAttributeBinding ).getRelationalValueBindings().iterator();
|
||||
}
|
||||
for ( RelationalValueSource valueSource : attributeSource.getKeySource().getValueSources() ) {
|
||||
Value targetValue = null;
|
||||
if ( targetValueBindings != null ) {
|
||||
if ( ! targetValueBindings.hasNext() ) {
|
||||
throw new MappingException(
|
||||
String.format(
|
||||
"More collection key source columns than target columns for collection: %s",
|
||||
pluralAttributeBinding.getAttribute().getRole()
|
||||
),
|
||||
currentBindingContext.getOrigin()
|
||||
);
|
||||
}
|
||||
targetValue = targetValueBindings.next().getValue();
|
||||
}
|
||||
Value targetValue = targetValueBindings.next().getValue();
|
||||
if ( ColumnSource.class.isInstance( valueSource ) ) {
|
||||
final ColumnSource columnSource = ColumnSource.class.cast( valueSource );
|
||||
final Column column = makeColumn(
|
||||
columnSource,
|
||||
COLL_KEY_COLUMN_BINDING_DEFAULTS,
|
||||
final Column column = makeColumn(
|
||||
columnSource,
|
||||
COLL_KEY_COLUMN_BINDING_DEFAULTS,
|
||||
pluralAttributeBinding.getCollectionTable(),
|
||||
pluralAttributeBinding.getAttribute().getName(),
|
||||
pluralAttributeBinding.getAttribute().getName(),
|
||||
true
|
||||
);
|
||||
if ( targetValue != null && ! Column.class.isInstance( targetValue ) ) {
|
||||
@ -1108,7 +1153,6 @@ private void bindCollectionKey(
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static final ColumnBindingDefaults COLL_KEY_COLUMN_BINDING_DEFAULTS = new ColumnBindingDefaults() {
|
||||
@Override
|
||||
public boolean areValuesIncludedInInsertByDefault() {
|
||||
@ -1166,7 +1210,8 @@ private void bindBasicPluralElementRelationalValues(
|
||||
createSimpleRelationalValues(
|
||||
relationalValueSourceContainer,
|
||||
elementBinding.getPluralAttributeBinding().getContainer(),
|
||||
elementBinding.getPluralAttributeBinding().getAttribute()
|
||||
elementBinding.getPluralAttributeBinding().getAttribute(),
|
||||
elementBinding.getPluralAttributeBinding().getCollectionTable()
|
||||
)
|
||||
);
|
||||
}
|
||||
@ -1440,23 +1485,26 @@ private void bindTableUniqueConstraints(EntitySource entitySource, EntityBinding
|
||||
private List<RelationalValueBinding> createSimpleRelationalValues(
|
||||
RelationalValueSourceContainer relationalValueSourceContainer,
|
||||
AttributeBindingContainer attributeBindingContainer,
|
||||
Attribute attribute) {
|
||||
Attribute attribute,
|
||||
TableSpecification defaultTable) {
|
||||
|
||||
List<RelationalValueBinding> valueBindings = new ArrayList<RelationalValueBinding>();
|
||||
|
||||
if ( !relationalValueSourceContainer.relationalValueSources().isEmpty() ) {
|
||||
for ( RelationalValueSource valueSource : relationalValueSourceContainer.relationalValueSources() ) {
|
||||
final TableSpecification table = attributeBindingContainer
|
||||
.seekEntityBinding()
|
||||
.locateTable( valueSource.getContainingTableName() );
|
||||
|
||||
TableSpecification resolvedTable = defaultTable;
|
||||
if ( valueSource.getContainingTableName() != null ) {
|
||||
resolvedTable = attributeBindingContainer
|
||||
.seekEntityBinding()
|
||||
.locateTable( valueSource.getContainingTableName() );
|
||||
}
|
||||
if ( ColumnSource.class.isInstance( valueSource ) ) {
|
||||
final ColumnSource columnSource = ColumnSource.class.cast( valueSource );
|
||||
final Column column =
|
||||
makeColumn(
|
||||
columnSource,
|
||||
relationalValueSourceContainer,
|
||||
table,
|
||||
relationalValueSourceContainer,
|
||||
resolvedTable,
|
||||
attribute.getName(),
|
||||
true
|
||||
);
|
||||
@ -1474,7 +1522,7 @@ private List<RelationalValueBinding> createSimpleRelationalValues(
|
||||
else {
|
||||
valueBindings.add(
|
||||
new RelationalValueBinding(
|
||||
makeDerivedValue( ( (DerivedValueSource) valueSource ), table )
|
||||
makeDerivedValue( ( (DerivedValueSource) valueSource ), resolvedTable )
|
||||
)
|
||||
);
|
||||
}
|
||||
@ -1485,18 +1533,15 @@ private List<RelationalValueBinding> createSimpleRelationalValues(
|
||||
.getNamingStrategy()
|
||||
.propertyToColumnName( attribute.getName() );
|
||||
name = quoteIdentifier( name );
|
||||
Column column = attributeBindingContainer
|
||||
.seekEntityBinding()
|
||||
.getPrimaryTable()
|
||||
.locateOrCreateColumn( name );
|
||||
Column column = defaultTable.locateOrCreateColumn( name );
|
||||
column.setNullable( relationalValueSourceContainer.areValuesNullableByDefault() );
|
||||
valueBindings.add( new RelationalValueBinding( column ) );
|
||||
}
|
||||
return valueBindings;
|
||||
}
|
||||
|
||||
private String quoteIdentifier(String identifier) {
|
||||
return currentBindingContext.isGloballyQuotedIdentifiers() ? StringHelper.quote( identifier ) : identifier;
|
||||
private String quoteIdentifier(String string) {
|
||||
return currentBindingContext.isGloballyQuotedIdentifiers() ? StringHelper.quote( string ) : string;
|
||||
}
|
||||
|
||||
private Value makeRelationalValue(
|
||||
|
@ -40,8 +40,7 @@ public class PluralAttributeKeyBinding {
|
||||
// may need notion of "boolean updatable"
|
||||
|
||||
// this knowledge can be implicitly resolved based on the typing information on the referenced owner attribute
|
||||
private HibernateTypeDescriptor hibernateTypeDescriptor;
|
||||
// in which case add this...
|
||||
private final HibernateTypeDescriptor hibernateTypeDescriptor = new HibernateTypeDescriptor();
|
||||
// SingularAttributeBinding referencedAttributeBinding;
|
||||
|
||||
// todo : this would be nice to have but we do not always know it, especially in HBM case.
|
||||
@ -89,7 +88,7 @@ public HibernateTypeDescriptor getHibernateTypeDescriptor() {
|
||||
return hibernateTypeDescriptor;
|
||||
}
|
||||
|
||||
public void prepareForeignKey(String foreignKeyName, String targetTableName) {
|
||||
public void prepareForeignKey(String foreignKeyName, TableSpecification targetTable) {
|
||||
if ( foreignKey != null ) {
|
||||
throw new AssertionFailure( "Foreign key already initialized" );
|
||||
}
|
||||
@ -105,10 +104,6 @@ public void prepareForeignKey(String foreignKeyName, String targetTableName) {
|
||||
}
|
||||
}
|
||||
|
||||
final TableSpecification targetTable = pluralAttributeBinding.getContainer()
|
||||
.seekEntityBinding()
|
||||
.locateTable( targetTableName );
|
||||
|
||||
foreignKey = collectionTable.createForeignKey( targetTable, foreignKeyName );
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,8 @@
|
||||
*/
|
||||
package org.hibernate.metamodel.spi.binding;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@ -30,13 +32,19 @@
|
||||
import org.hibernate.metamodel.MetadataSourceProcessingOrder;
|
||||
import org.hibernate.metamodel.MetadataSources;
|
||||
import org.hibernate.metamodel.internal.MetadataImpl;
|
||||
import org.hibernate.metamodel.spi.relational.Column;
|
||||
import org.hibernate.metamodel.spi.relational.ForeignKey;
|
||||
import org.hibernate.metamodel.spi.relational.Identifier;
|
||||
import org.hibernate.service.ServiceRegistryBuilder;
|
||||
import org.hibernate.service.internal.StandardServiceRegistryImpl;
|
||||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
@ -77,14 +85,64 @@ private void doTest(MetadataSourceProcessingOrder processingOrder) {
|
||||
assertNotNull( bagBinding );
|
||||
assertSame( bagBinding, entityBinding.locateAttributeBinding( "theBag" ) );
|
||||
assertNotNull( bagBinding.getCollectionTable() );
|
||||
assertEquals( Identifier.toIdentifier( "`EntityWithBasicCollections_theBag`" ), bagBinding.getCollectionTable().getLogicalName() );
|
||||
PluralAttributeKeyBinding bagKeyBinding = bagBinding.getPluralAttributeKeyBinding();
|
||||
assertSame( bagBinding, bagKeyBinding.getPluralAttributeBinding() );
|
||||
|
||||
ForeignKey fkBag = bagKeyBinding.getForeignKey();
|
||||
assertNotNull( fkBag );
|
||||
assertSame( bagBinding.getCollectionTable(), fkBag.getSourceTable() );
|
||||
assertEquals( 1, fkBag.getColumnSpan() );
|
||||
Iterator<Column> fkBagColumnIterator = fkBag.getColumns().iterator();
|
||||
Iterator<Column> fkBagSourceColumnIterator = fkBag.getSourceColumns().iterator();
|
||||
assertNotNull( fkBagColumnIterator );
|
||||
assertNotNull( fkBagSourceColumnIterator );
|
||||
assertTrue( fkBagColumnIterator.hasNext() );
|
||||
assertTrue( fkBagSourceColumnIterator.hasNext() );
|
||||
assertEquals( Identifier.toIdentifier( "`owner_id`" ), fkBagColumnIterator.next().getColumnName() );
|
||||
assertEquals( Identifier.toIdentifier( "`owner_id`" ), fkBagSourceColumnIterator.next().getColumnName() );
|
||||
assertFalse( fkBagColumnIterator.hasNext() );
|
||||
assertFalse( fkBagSourceColumnIterator.hasNext() );
|
||||
assertSame( entityBinding.getPrimaryTable(), fkBag.getTargetTable() );
|
||||
assertEquals( entityBinding.getPrimaryTable().getPrimaryKey().getColumns(), fkBag.getTargetColumns() );
|
||||
assertSame( ForeignKey.ReferentialAction.NO_ACTION, fkBag.getDeleteRule() );
|
||||
assertSame( ForeignKey.ReferentialAction.NO_ACTION, fkBag.getUpdateRule() );
|
||||
// FK is null because no default FK name is generated until HHH-7092 is fixed
|
||||
assertNull( fkBag.getName() );
|
||||
assertFalse( bagKeyBinding.isInverse() );
|
||||
assertEquals( PluralAttributeElementNature.BASIC, bagBinding.getPluralAttributeElementBinding().getPluralAttributeElementNature() );
|
||||
assertEquals( String.class.getName(), ( (BasicPluralAttributeElementBinding) bagBinding.getPluralAttributeElementBinding() ).getHibernateTypeDescriptor().getJavaTypeName() );
|
||||
assertEquals( String.class.getName(), bagBinding.getPluralAttributeElementBinding().getHibernateTypeDescriptor().getJavaTypeName() );
|
||||
|
||||
PluralAttributeBinding setBinding = metadata.getCollection( EntityWithBasicCollections.class.getName() + ".theSet" );
|
||||
assertNotNull( setBinding );
|
||||
assertSame( setBinding, entityBinding.locateAttributeBinding( "theSet" ) );
|
||||
assertNotNull( setBinding.getCollectionTable() );
|
||||
assertEquals( Identifier.toIdentifier( "`EntityWithBasicCollections_theSet`" ), setBinding.getCollectionTable().getLogicalName() );
|
||||
PluralAttributeKeyBinding setKeyBinding = setBinding.getPluralAttributeKeyBinding();
|
||||
assertSame( setBinding, setKeyBinding.getPluralAttributeBinding() );
|
||||
|
||||
ForeignKey fkSet = setKeyBinding.getForeignKey();
|
||||
assertNotNull( fkSet );
|
||||
assertSame( setBinding.getCollectionTable(), fkSet.getSourceTable() );
|
||||
assertEquals( 1, fkSet.getColumnSpan() );
|
||||
Iterator<Column> fkSetColumnIterator = fkSet.getColumns().iterator();
|
||||
Iterator<Column> fkSetSourceColumnIterator = fkSet.getSourceColumns().iterator();
|
||||
assertNotNull( fkSetColumnIterator );
|
||||
assertNotNull( fkSetSourceColumnIterator );
|
||||
assertTrue( fkSetColumnIterator.hasNext() );
|
||||
assertTrue( fkSetSourceColumnIterator.hasNext() );
|
||||
assertEquals( Identifier.toIdentifier( "`pid`" ), fkSetColumnIterator.next().getColumnName() );
|
||||
assertEquals( Identifier.toIdentifier( "`pid`" ), fkSetSourceColumnIterator.next().getColumnName() );
|
||||
assertFalse( fkSetColumnIterator.hasNext() );
|
||||
assertFalse( fkSetSourceColumnIterator.hasNext() );
|
||||
assertSame( entityBinding.getPrimaryTable(), fkSet.getTargetTable() );
|
||||
assertEquals( entityBinding.getPrimaryTable().getPrimaryKey().getColumns(), fkSet.getTargetColumns() );
|
||||
assertSame( ForeignKey.ReferentialAction.NO_ACTION, fkSet.getDeleteRule() );
|
||||
assertSame( ForeignKey.ReferentialAction.NO_ACTION, fkSet.getUpdateRule() );
|
||||
// FK is null because no default FK name is generated until HHH-7092 is fixed
|
||||
assertNull( fkSet.getName() );
|
||||
assertFalse( setKeyBinding.isInverse() );
|
||||
assertEquals( PluralAttributeElementNature.BASIC, setBinding.getPluralAttributeElementBinding().getPluralAttributeElementNature() );
|
||||
assertEquals( String.class.getName(), ( (BasicPluralAttributeElementBinding) setBinding.getPluralAttributeElementBinding() ).getHibernateTypeDescriptor().getJavaTypeName() );
|
||||
assertEquals( String.class.getName(), setBinding.getPluralAttributeElementBinding().getHibernateTypeDescriptor().getJavaTypeName() );
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user